<?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=Smirnov.maxim</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=Smirnov.maxim"/>
	<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/Smirnov.maxim"/>
	<updated>2026-10-22T23:26:04Z</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:Smirnov.maxim/BIRCH&amp;diff=20779</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20779"/>
		<updated>2016-12-12T19:17:12Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. График времени работы параллельной реализации алгоритма BIRCH. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. График эффективности распараллеливания алгоритма BIRCH относительно последовательной реализации. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. При количестве процессов &amp;lt;math&amp;gt;n&amp;gt;30&amp;lt;/math&amp;gt; темп снижения становится несущественным.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
! Технические детали реализации&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
Компилятор: intel/15.0.090&lt;br /&gt;
&lt;br /&gt;
Версия реализации MPI: openmpi/1.10.2-icc&lt;br /&gt;
&lt;br /&gt;
Планировщик задач: slurm/2.5.6&lt;br /&gt;
&lt;br /&gt;
Очереди: test, regular4&lt;br /&gt;
&lt;br /&gt;
Команда компиляции: mpicxx -std=c++11 -Wall &amp;lt;source_files&amp;gt; -o &amp;lt;executable&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда запуска: sbatch -n &amp;lt;num_of_processes&amp;gt; -p &amp;lt;queue&amp;gt; -o &amp;lt;log_file&amp;gt; ompi &amp;lt;executable&amp;gt; &amp;lt;args&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20778</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20778"/>
		<updated>2016-12-12T19:16:40Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. График времени работы параллельной реализации алгоритма BIRCH. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. График эффективности распараллеливания алгоритма BIRCH относительно последовательной реализации. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. При количестве процессов &amp;lt;math&amp;gt;n&amp;gt;30&amp;lt;/math&amp;gt; темп снижения становится несущественным.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
! Технические детали реализации&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
Компилятор: intel/15.0.090&lt;br /&gt;
&lt;br /&gt;
Версия реализации MPI: openmpi/1.10.2-icc&lt;br /&gt;
&lt;br /&gt;
Планировщик задач: slurm/2.5.6&lt;br /&gt;
&lt;br /&gt;
Очереди: test, regular4&lt;br /&gt;
&lt;br /&gt;
Команда компиляции: mpicxx -std=c++11 -Wall &amp;lt;source_files&amp;gt; -o &amp;lt;executable&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда запуска: sbatch -n &amp;lt;num_of_processes&amp;gt; -p &amp;lt;queue&amp;gt; -o &amp;lt;log_file&amp;gt; ompi &amp;lt;executable&amp;gt; &amp;lt;args&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20642</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20642"/>
		<updated>2016-12-11T16:17:47Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. График времени работы параллельной реализации алгоритма BIRCH. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. График эффективности распараллеливания алгоритма BIRCH относительно последовательной реализации. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. При количестве процессов &amp;lt;math&amp;gt;n&amp;gt;30&amp;lt;/math&amp;gt; темп снижения становятся несущественным.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20641</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20641"/>
		<updated>2016-12-11T16:17:28Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. График времени работы параллельной реализации алгоритма BIRCH. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. График эффективности распараллеливания алгоритма BIRCH относительно последовательной реализации. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. При количестве процессов &amp;lt;math&amp;gt;n&amp;gt;30&amp;lt;/math&amp;gt; темп снижения становятся несущественным.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20640</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20640"/>
		<updated>2016-12-11T16:14:55Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная производительность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. При количестве процессов &amp;lt;math&amp;gt;n&amp;gt;30&amp;lt;/math&amp;gt; темп снижения становятся несущественным.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20639</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20639"/>
		<updated>2016-12-11T16:12:11Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная производительность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
Полученные результаты могут быть объяснены недерминированностью алгоритма BIRCH и существенной зависимостью времени его работы от входных данных.&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости параллельной реализации:&lt;br /&gt;
*	По числу процессов:  при увеличении числа процессов эффективность распараллеливания снижается. По мере увеличения числа процессов темпы снижения становятся несущественными.&lt;br /&gt;
* По размеру задачи: при увеличении размера входных данных эффективность растет неравномерно, что свидетельствует о сложной зависимости от входных данных.&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20635</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20635"/>
		<updated>2016-12-11T15:58:16Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная производительность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости&lt;br /&gt;
*	По числу процессов&lt;br /&gt;
&lt;br /&gt;
Для исследования возможностей паралеллизма алгоритма BIRCH была написана [https://github.com/duran-duran/birch реализация на языке C++] с использованием технологии MPI. В данной реализации входные данные равномерно распределяются между всеми процессами, в каждом из которых выполняется построение собственного кластерного дерева. Листьевые элементы полученных деревьев затем подвергаются глобальной кластеризации с помощью распределенного алгоритма k-средних. В качестве входных данных использовались точки размерности &amp;lt;math&amp;gt;d=5&amp;lt;/math&amp;gt;, координаты которых были равномерно распределены в диапазоне &amp;lt;math&amp;gt;[-10000;10000]&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;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=20633</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=20633"/>
		<updated>2016-12-11T15:47:54Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов Максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма BIRCH. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot;&amp;lt;ref name=&amp;quot;Lom&amp;quot;&amp;gt;Воеводин Вл., Жуматий С., Соболев С., Антонов А., Брызгалов П., Никитенко Д., Стефанов К., Воеводин Вад. Практика суперкомпьютера «Ломоносов» // Открытые системы, 2012, N 7, С. 36-39.&amp;lt;/ref&amp;gt; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Производительность.png|thumb|center|700px|Рисунок 1. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная производительность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость параллельной реализации алгоритма BIRCH. Эффективность.png|thumb|center|700px|Рисунок 2. Масштабируемость параллельной реализации алгоритма BIRCH. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Набор изменяемых параметров запуска реализации алгоритма и границы значений параметров алгоритма: &lt;br /&gt;
*	число процессоров [8 : 80] с шагом 8&lt;br /&gt;
*	число точек [100 000 : 1 000 000] с шагом 100 000&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
*	минимальная эффективность реализации 9,13% (80 процессоров, 100 000 точек)&lt;br /&gt;
*	максимальная эффективность реализации 235,42% (8 процессоров, 800 000 точек)&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;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=17227</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=17227"/>
		<updated>2016-11-15T11:53:33Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=17226</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=17226"/>
		<updated>2016-11-15T11:51:19Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Вычислительная сложность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм BIRCH не является детерминированным, так как процесс его выполнения во многом зависит от входных данных.&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=17217</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=17217"/>
		<updated>2016-11-15T11:31:42Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Достоинства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
К достоинствам алгоритма можно отнести следующие его свойства:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=17216</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=17216"/>
		<updated>2016-11-15T11:30:22Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Недостатки алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
В свою очередь, недостатки алгоритма можно сформулировать следующим образом:&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=16296</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=16296"/>
		<updated>2016-11-10T08:02:07Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации // Интеллектуальные технологии и системы. Сборник учебно-методических работ и статей аспирантов и студентов. – М.: НОК «CLAIM», 2006. – Выпуск 8. – С. 130-142.&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt; - алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15871</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15871"/>
		<updated>2016-11-03T09:05:21Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15870</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15870"/>
		<updated>2016-11-03T09:04:27Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N \cdot SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1 \cdot SS_2 + N_2 \cdot SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1 \cdot N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15869</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15869"/>
		<updated>2016-11-03T09:03:15Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;N \cdot d&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15868</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15868"/>
		<updated>2016-11-03T09:02:56Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;Nd&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Вычислительная сложность ===&lt;br /&gt;
&lt;br /&gt;
Вычислительная сложность алгоритма имеет порядок &amp;lt;math&amp;gt;O(\frac{d \cdot B \cdot (1+log_B\frac{M}{P}) \cdot (N +log_2\frac{N}{N_0} \cdot \frac{M}{ES})}{N \cdot d + M})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15867</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15867"/>
		<updated>2016-11-03T08:56:12Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 алгоритма будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;Nd&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15866</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15866"/>
		<updated>2016-11-03T08:53:13Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Таким образом, параллельная сложность фазы 1 будет равна &amp;lt;math&amp;gt;O((N + log_2\frac{N}{N_0} \cdot \frac{M}{ES})(log_2 B + log_2 d)(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;Nd&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15865</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15865"/>
		<updated>2016-11-03T08:42:58Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
Вклад авторов:&lt;br /&gt;
&lt;br /&gt;
Смирнов максим:&lt;br /&gt;
*п.1.5&lt;br /&gt;
*п.1.7&lt;br /&gt;
*п.1.8&lt;br /&gt;
*п.1.9&lt;br /&gt;
*п.2.7&lt;br /&gt;
&lt;br /&gt;
Морозова Светлана&lt;br /&gt;
*п.1.1&lt;br /&gt;
*п.1.2&lt;br /&gt;
*п.1.3&lt;br /&gt;
*п.1.4&lt;br /&gt;
*п.1.6&lt;br /&gt;
*п.1.10&lt;br /&gt;
*п.3&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases - 1996. - С.103-114)&amp;lt;/ref&amp;gt;- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data //10th International Database Engineering and Applications Symposium (IDEAS&#039;06), 2006&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039; набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;Nd&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039; кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных:&#039;&#039;&#039; &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=15014</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=15014"/>
		<updated>2016-10-31T10:14:43Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13926</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13926"/>
		<updated>2016-10-26T11:28:41Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d \cdot N \cdot B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0} \cdot d \cdot \frac{M}{ES} \cdot B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N \cdot K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
=== Вычисление расстояния ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2=\frac{N_1\cdot SS_2+N_2\cdot SS_1-2 \cdot \vec{LS_1}\cdot \vec{LS_2}}{N_1\cdot N_2}&amp;lt;/math&amp;gt;, где&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_1=[N_1,\vec{LS_1},SS_1]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_2=[N_2,\vec{LS_2},SS_2]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:ZgYL51QJsQk.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
=== Поиск ближайшего подкластера ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;E&amp;lt;/math&amp;gt; - новый элемент&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF_i, i = 1,...,B&amp;lt;/math&amp;gt; - подкластеры узла&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; - операция min&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\rho&amp;lt;/math&amp;gt; - нахождение расстояния&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:PFA16KHUQ3I.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Скалярное произведение ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;s = \vec{x}\cdot\vec{y}=\sum_{i=1}^d x_i\cdot y_i&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Xb7FYXVMPpQ.jpg|600px|thumb|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13783</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13783"/>
		<updated>2016-10-25T16:20:45Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; - ограничение по памяти на размер узла, а &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt; - общий объем памяти. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13780</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13780"/>
		<updated>2016-10-25T16:19:14Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Кластерное дерево */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13773</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13773"/>
		<updated>2016-10-25T16:11:53Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Кластерное дерево */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Параметры дерева, в свою очередь, определяются ограничением по памяти на размер узла &amp;lt;math&amp;gt;P&amp;lt;/math&amp;gt; и общим объемом памяти &amp;lt;math&amp;gt;M&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13755</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13755"/>
		<updated>2016-10-25T15:37:39Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]].&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13747</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13747"/>
		<updated>2016-10-25T15:25:18Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;\vec{LS},\vec{X0}, R, D, D_0-D_4&amp;lt;/math&amp;gt;, в процессе чего выполняются операции сложения и скалярного произведения векторов.&lt;br /&gt;
&lt;br /&gt;
Другим способом параллелизации алгоритма может служить создание и заполнение сразу множества кластерных деревьев, между которыми будут распределены входные данные. Множество всех подкластеров листьевых узлов полученных таким образом деревьев может быть подвергнуто глобальной кластеризации с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13683</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13683"/>
		<updated>2016-10-25T12:40:08Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* ЧАСТЬ. Свойства и структура алгоритмов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Так как вставка новых элементов в кластерное дерево не может быть осуществлена иначе как последовательно, естественным способом параллелизации алгоритма является создание и заполнение сразу множества деревьев, между которыми будут распределены входные данные. Далее может быть произведена глобальная кластеризация множества подкластеров листьевых узлов всех деревьев с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13682</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13682"/>
		<updated>2016-10-25T12:39:53Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* ЧАСТЬ. Программная реализация алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Так как вставка новых элементов в кластерное дерево не может быть осуществлена иначе как последовательно, естественным способом параллелизации алгоритма является создание и заполнение сразу множества деревьев, между которыми будут распределены входные данные. Далее может быть произведена глобальная кластеризация множества подкластеров листьевых узлов всех деревьев с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13681</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13681"/>
		<updated>2016-10-25T12:39:07Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Литература */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Так как вставка новых элементов в кластерное дерево не может быть осуществлена иначе как последовательно, естественным способом параллелизации алгоритма является создание и заполнение сразу множества деревьев, между которыми будут распределены входные данные. Далее может быть произведена глобальная кластеризация множества подкластеров листьевых узлов всех деревьев с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13680</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13680"/>
		<updated>2016-10-25T12:38:46Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Так как вставка новых элементов в кластерное дерево не может быть осуществлена иначе как последовательно, естественным способом параллелизации алгоритма является создание и заполнение сразу множества деревьев, между которыми будут распределены входные данные. Далее может быть произведена глобальная кластеризация множества подкластеров листьевых узлов всех деревьев с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13677</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13677"/>
		<updated>2016-10-25T12:38:02Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
Так как вставка новых элементов в кластерное дерево не может быть осуществлена иначе как последовательно, естественным способом параллелизации алгоритма является создание и заполнение сразу множества деревьев, между которыми будут распределены входные данные. Далее может быть произведена глобальная кластеризация множества подкластеров листьевых узлов всех деревьев с помощью какого-либо из известных параллельных алгоритмов, например, k-средних&amp;lt;ref&amp;gt;[http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13676</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13676"/>
		<updated>2016-10-25T12:36:39Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039;&amp;lt;ref&amp;gt;[http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;[http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&amp;lt;/ref&amp;gt; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13653</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13653"/>
		<updated>2016-10-25T11:37:19Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
Последовательную реализацию основных операций алгоритма BIRCH можно продемонстрировать на примере следующего фрагмента кода на языке C++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13651</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13651"/>
		<updated>2016-10-25T11:31:32Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
void CF_Node::insert(const CF_Cluster &amp;amp;entry)&lt;br /&gt;
{&lt;br /&gt;
    //Находим ближайший к новому элементу подкластер в узле&lt;br /&gt;
    СF_Vector_it closest = entry.findClosest(subclusters);&lt;br /&gt;
    //Если узел пустой, добавляем в него новый подкластер&lt;br /&gt;
    if (closest == subclusters.end()) {&lt;br /&gt;
        subclusters.push_back(entry);&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    closest-&amp;gt;add(entry);&lt;br /&gt;
    //Если узел является листьевым, и ближайший подкластер не может вместить&lt;br /&gt;
    //новый элемент, добавляем в узел новый подкластер&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (closest-&amp;gt;D &amp;gt; threshold) {&lt;br /&gt;
            closest-&amp;gt;remove(entry);&lt;br /&gt;
            subclusters.push_back(entry);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        CF_Node *node = closest-&amp;gt;child;&lt;br /&gt;
        node-&amp;gt;insert(entry);&lt;br /&gt;
        //Если при добавлении нового элемента в дочерний узел тот переполнился,&lt;br /&gt;
        //расщепляем его        &lt;br /&gt;
        if (node-&amp;gt;getSubclusters().size() &amp;gt; bFactor) {&lt;br /&gt;
            CF_Vector newClusters = node-&amp;gt;splitNode();&lt;br /&gt;
            delete node;&lt;br /&gt;
            subclusters.erase(closest);&lt;br /&gt;
            subclusters.insert(subclusters.end(), newClusters.begin(), newClusters.end());&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Если узел является корневым и он переполнен, расщепляем его&lt;br /&gt;
    if (root &amp;amp;&amp;amp; subclusters.size() &amp;gt; bFactor) {&lt;br /&gt;
        subclusters = splitNode();&lt;br /&gt;
        leaf = false;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
CF_Vector CF_Node::splitNode()&lt;br /&gt;
{&lt;br /&gt;
    if (subclusters.size() &amp;lt; 2)&lt;br /&gt;
        return (root) ? subclusters : CF_Vector{CF_Cluster(this)};&lt;br /&gt;
    //Находим пару наиболее удаленных друг от друга подкластеров&lt;br /&gt;
    CF_Vector_it pole1, pole2;&lt;br /&gt;
    data_t longestDist = 0.0;&lt;br /&gt;
    for (auto lhs = subclusters.begin(); lhs != subclusters.end() - 1; ++lhs) {&lt;br /&gt;
        for (auto rhs = lhs + 1; rhs != subclusters.end(); ++rhs) {&lt;br /&gt;
            auto distance = getDistance(*lhs, *rhs);&lt;br /&gt;
            if (distance &amp;gt; longestDist) {&lt;br /&gt;
                longestDist = distance;&lt;br /&gt;
                pole1 = lhs;&lt;br /&gt;
                pole2 = rhs;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    //Разделяем множество всех подкластеров узла на две части&lt;br /&gt;
    CF_Vector subclusters1, subclusters2;&lt;br /&gt;
    for (auto it = subclusters.begin(); it != subclusters.end(); ++it) {&lt;br /&gt;
        if (getDistance(*it, *pole1) &amp;lt; getDistance(*it, *pole2))&lt;br /&gt;
            subclusters1.push_back(*it);&lt;br /&gt;
        else&lt;br /&gt;
            subclusters2.push_back(*it);&lt;br /&gt;
    }&lt;br /&gt;
    //Создаем два новых узла&lt;br /&gt;
    CF_Node *node1 = new CF_Node(threshold, bFactor, count, leaf, subclusters1),&lt;br /&gt;
            *node2 = new CF_Node(threshold, bFactor, count, leaf, subclusters2);&lt;br /&gt;
    //Связываем листья&lt;br /&gt;
    if (leaf) {&lt;br /&gt;
        if (prevLeaf) {&lt;br /&gt;
            node1-&amp;gt;setPrevLeaf(prevLeaf);&lt;br /&gt;
            prevLeaf-&amp;gt;setNextLeaf(node1);&lt;br /&gt;
        }&lt;br /&gt;
        if (nextLeaf) {&lt;br /&gt;
            node2-&amp;gt;setNextLeaf(nextLeaf);&lt;br /&gt;
            nextLeaf-&amp;gt;setPrevLeaf(node2);&lt;br /&gt;
        }&lt;br /&gt;
        node1-&amp;gt;setNextLeaf(node2);&lt;br /&gt;
        node2-&amp;gt;setPrevLeaf(node1);&lt;br /&gt;
    }&lt;br /&gt;
    CF_Cluster cluster1(node1), cluster2(node2);&lt;br /&gt;
    return CF_Vector{cluster1, cluster2};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13643</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13643"/>
		<updated>2016-10-25T10:39:34Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&#039;&#039;&#039;Входные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Набор из &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек &amp;lt;math&amp;gt;\{X_i\}, i=1,...,N&amp;lt;/math&amp;gt; размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Кластерное дерево с не более чем &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt; узлами.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13641</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13641"/>
		<updated>2016-10-25T10:17:20Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Макроструктура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Реализация алгоритма BIRCH состояит из следующих четырёх фаз:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 1&#039;&#039;&#039;. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево стремится отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. При этом плотно распределённые данные группируются в подкластеры, а более разрозненные данные удаляются. После завершения фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально (в соответствии с доступным количеством памяти);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 2&#039;&#039;&#039;. Данная фаза является опциональной. Известно, что существующие методы глобальной кластеризации, используемые в рамках фазы 3, имеют различные диапазоны входных значений, при которых их реализация наиболее эффективна. Поэтому потенциально существует пробел между размером фазы 1 и входными значениями фазы 3. И фаза 2 как раз является недостающим связующим звеном: так же как и фаза 1, она сканирует листьевые элементы начального CF дерева для того, чтобы построить меньшее дерево, удаляя ещё больше элементов с низкой плотностью и группируя переполненные подкластеры в большие кластеры.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 3&#039;&#039;&#039;. В данной фазе для листьевых элементов применяется (любой подходящий) алгоритм глобальной кластеризации. Существующие алгоритмы кластеризации наборов точек могут также работать с наборами подкластеров, каждый из которых представлен своим CF вектором. Зная CF вектор, можно вычислить центроид и в дальнейшем заменить всю информацию о кластере этим значением (этого достаточно для вычисления большинства необходимых метрик). После фазы 3 мы получаем набор кластеров, который отражает основные характеристики распределяемых данных.&lt;br /&gt;
Однако, всё ещё могут оставаться некоторые неточности, для устранения которых существует фаза 4.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Фаза 4&#039;&#039;&#039;. Данная фаза является опциональной и влечёт за собой затраты на дополнительное сканирование данных для корректировки неточностей и дальнейшего улучшения кластеризации. Фаза 4 использует центроиды кластеров, полученные в фазе 3 для как основы и перераспределяет точки входных данных в ближайшие для них основы для получения нового списка кластеров. Фаза 4, если это необходимо пользователю, может быть расширена дополнительными проходами для уверенности в том, что результат приближается к оптимальному.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для начала проанализируем вычислительную сложность фазы 1.&lt;br /&gt;
Максимальный размер дерева &amp;lt;math&amp;gt;\frac{M}{P}&amp;lt;/math&amp;gt;. Для того чтобы вставить элемент, мы должны пройти путь от корня до листа (это около &amp;lt;math&amp;gt;1+log_B\frac{M}{P}&amp;lt;/math&amp;gt; узлов). В каждом узле в поисках &amp;quot;ближайшего&amp;quot; нам необходимо просмотреть B элементов; сложность для каждого элемента пропорциональна размерности &#039;&#039;d&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Поэтому сложность вставки всех входных точек &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В случае, когда необходимо перестроить дерево, предположим, что ES - это размер CF элемента. Существует максимум &amp;lt;math&amp;gt;\frac{M}{ES}&amp;lt;/math&amp;gt; листьевых элементов для вставки, поэтому сложность повторной вставки листьевых элементов &amp;lt;math&amp;gt;O(d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Количество итераций перестройки дерева зависит от пороговой величины. На самом деле, это около &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; (двоичное основание появилось из-за того, что мы не можем провести оценку более чем в 2 раза отличающуюся от текущего размера). &amp;lt;math&amp;gt;N_0&amp;lt;/math&amp;gt; - это число входных точек, загруженных в память с пороговым ограничением &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Соответственно, итоговая сложность фазы 1 &amp;lt;math&amp;gt;O(d*N*B(1+log_B\frac{M}{P})+log_2\frac{N}{N_0}*d*\frac{M}{ES}*B(1+log_B\frac{M}{P}))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Анализ фазы 2 проводится аналогично.&lt;br /&gt;
&lt;br /&gt;
Что касается операций ввода-вывода, то в фазе 1 данные сканируются один раз, а в фазе 2 не сканируются вовсе.&lt;br /&gt;
Некоторое количество вычислений связано с удалением точек из областей с низкой плотностью.&lt;br /&gt;
Если количество доступной для этой операции памяти не больше &#039;&#039;M&#039;&#039; и проведено порядка &amp;lt;math&amp;gt;log_2\frac{N}{N_0}&amp;lt;/math&amp;gt; перестроек дерева, то сложность ввода-вывода для фазы 1 существенно не отличается от сложности чтения из файла. Основываясь рассуждениях выше, сложность фаз 1 и 2 будет линейно увеличиваться с ростом N.&lt;br /&gt;
&lt;br /&gt;
В фазе 3 нет операций ввода-вывода. Её сложность ограничена константой, которая зависит от максимального размера входных данных, и варианта выбранного алгоритма для кластеризации. &lt;br /&gt;
&lt;br /&gt;
Фаза 4 снова сканирует данные и записывает каждую точку в подходящий кластер; время работы пропорционально &amp;lt;math&amp;gt;N*K&amp;lt;/math&amp;gt;.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
=== Недостатки алгоритма ===&lt;br /&gt;
&lt;br /&gt;
1. Алгоритм позволяет работать только с числовыми данными.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH хорошо выделяет только кластеры сферической формы.&lt;br /&gt;
&lt;br /&gt;
3. Существует необходимость в задании пороговых значений.&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;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
В составе пакетов и библиотек:&lt;br /&gt;
* [http://scikit-learn.org/stable/modules/generated/sklearn.cluster.Birch.html scikit-learn]&lt;br /&gt;
* [http://cucis.ece.northwestern.edu/projects/DMS/MineBench.html NU-MineBench]&lt;br /&gt;
Пользовательские реализации:&lt;br /&gt;
* [https://code.google.com/archive/p/jbirch/ JBIRCH]&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.sfu.ca/CourseCentral/459/han/papers/zhang96.pdf T Zhang, R Ramakrishnan, M Livny. BIRCH: An Efficient Data Clustering Method for Very Large Databases]&lt;br /&gt;
* [http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf Нейский И.М. Классификация и сравнение методов кластеризации]&lt;br /&gt;
* [http://people.du.ac.in/~ngupta/Publications/PBIRCH%20A%20Sacalabel%20Paralllel%20Clustering.pdf A Garg, N Gupta PBIRCH: A Scalable Parallel Clustering algorithm for Incremental Data]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13455</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13455"/>
		<updated>2016-10-22T17:07:39Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из рассмотренных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13454</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13454"/>
		<updated>2016-10-22T17:05:33Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из предложенных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате элементарных алгебраических преобразований можно получить следующие упрощенные формулы вычисления необходимых значений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13453</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13453"/>
		<updated>2016-10-22T17:03:25Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки элемнта &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм доходит до листа, он находит ближайшую листьевой элемент, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, можно ли добавить &#039;&#039;Ent&#039;&#039; к &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt; без нарушения порогового условия. Если да, то с учётом этого изменяется CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;; если нет, то &#039;&#039;Ent&#039;&#039; становится новым элементом листа. Если в листе для этого достаточно места, то шаг окончен, иначе он должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора за основу наиболее удалённой друг от друга пары элементов и перераспределение оставшихся элементов в соответствии с выбранным критерием близости.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждого нелистьевого элемента на пути к листу. При отсутствии расщепления это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление листа же требует вставки нового нелистьевого элемента в родительский узел для задания только что созданного листа. Если у родителя есть место для этого элемента, то необходимо просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Расщепление вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; может вместить дополнительный элемент, полученный после расщепления. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких элементов. Если это не пара, отвечающая расщеплению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если количество элементов в дочерних узлах  больше B, мы снова расщепляем результат объединения.&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;R&amp;lt;/math&amp;gt; или диаметра &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластерного элемента. Выполняется при попытке вставить новый элемент в один из подкластеров листьевого узла дерева.&lt;br /&gt;
&lt;br /&gt;
* расстояния между двумя элементами. Выполняется при поиске ближайшего по отношению к новому элементу подкластера в узле дерева по одной из предложенных в разд. 1.2.1 метрик &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Зная характеристики кластерных элементов &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, в результате элементарных алгебраических преобразований можно получить следующие упрощенные формулы вычисления некоторых необходимых величин:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\vec{X_0} = \frac{\vec{LS}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{SS - 2\vec{X_0}\vec{LS} + N(\vec{X_0})^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{2(N*SS - (\vec{LS})^2)}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{N_1*SS_2 + N_2*SS_1 - 2\vec{LS_1}\vec{LS_2}}{N_1*N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{2((N_1+N_2)(SS_1+SS_2)-(\vec{LS_1}+\vec{LS_2})^2)}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13445</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13445"/>
		<updated>2016-10-22T15:43:13Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Теоретическая основа ===&lt;br /&gt;
&lt;br /&gt;
Пусть в кластере имеются &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13444</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13444"/>
		<updated>2016-10-22T15:42:49Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Кластерные элементы и кластерное дерево */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&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;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерный элемент и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; [https://ru.wikipedia.org/wiki/B%2B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE дерево] использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13443</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13443"/>
		<updated>2016-10-22T15:13:59Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Теоретическая основа */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&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;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерные элементы и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\vec{X_i}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; дерево использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13442</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13442"/>
		<updated>2016-10-22T15:13:13Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Теоретическая основа */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&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;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. Данные величины являются альтернативными метриками плотности кластера относительно центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики:&lt;br /&gt;
&lt;br /&gt;
пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\{\vec{X_i}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\{\vec{X_j}\}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N_1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерные элементы и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\vec{X_i}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; дерево использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13441</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13441"/>
		<updated>2016-10-22T15:05:42Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Кластерные элементы и кластерное дерево */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&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;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\vec{X_i}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. То есть по сути это две альтернативные метрики плотности кластера вокруг центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики.&lt;br /&gt;
&lt;br /&gt;
Пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;{\vec{X_i}}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{\vec{X_j}}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерные элементы и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; и &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\vec{X_i}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; дерево использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim/BIRCH&amp;diff=13440</id>
		<title>Участник:Smirnov.maxim/BIRCH</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:Smirnov.maxim/BIRCH&amp;diff=13440"/>
		<updated>2016-10-22T15:05:11Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: /* Кластерные элементы и кластерное дерево */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Нахождение полезных для анализа закономерностей в больших объёмах данных с недавних пор вызывает значительный интерес. В связи с этим ввелось и стало активно развиваться такое понятие как &#039;&#039;[https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7 кластеризация]&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Ранние работы и алгоритмы, разработанные в этой области, не уделяли достаточного внимания анализу очень больших наборов данных или минимизации издержек на процессы ввода-вывода.&lt;br /&gt;
Решением этих проблем стал алгоритм, известный как BIRCH.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BIRCH&#039;&#039;&#039; (balanced iterative reducing and clustering using hierarchies)- алгоритм, применяемый в области [https://ru.wikipedia.org/wiki/Data_mining Data mining] и использующий принципы [https://ru.wikipedia.org/wiki/%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F иерархической кластеризации].&lt;br /&gt;
&lt;br /&gt;
Если имеется очень большой набор данных, то в пространстве он распределен, как правило, неравномерно. Кластерный анализ определяет места наибольшего и наименьшего скоплений, чтобы таким образом понять всю картину целиком. Кроме того, полученные кластеры визуализируются гораздо нагляднее, чем начальные &amp;quot;сырые&amp;quot; данные.&lt;br /&gt;
Задачей алгоритмов кластеризации является не только простое разбиение данных на кластеры, но и работа в рамках ограниченного объёма доступной памяти (как правило, её объём гораздо меньше, чем размер исходного набора данных) и минимизация времени, требуемого на операции ввода-вывода.&lt;br /&gt;
&lt;br /&gt;
Для наилучшего решения этих проблем BIRCH распределяет входящие данные по кластерам динамически. Для эффективной кластеризации алгоритму требуется всего одно сканирование данных (т.е. с увеличением количества данных сложность увеличивается линейно). А при помощи одной (или более) дополнительных итераций можно и далее улучшать эффективность. BIRCH также является первым алгоритмом, предложенным для эффективного управления &amp;quot;шумами&amp;quot; (данными, которые не вписываются в общее представление модели).&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;N&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;\vec{X_i}, i=1,2,...,N&amp;lt;/math&amp;gt;.&lt;br /&gt;
Тогда &#039;&#039;&#039;центроид&#039;&#039;&#039; &amp;lt;math&amp;gt;{\vec{{X_0}}}&amp;lt;/math&amp;gt;, &#039;&#039;&#039;радиус&#039;&#039;&#039; &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &#039;&#039;&#039;диаметр&#039;&#039;&#039; &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; кластера определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;{\vec{X_0}}=\frac{\sum_{i=1}^N\vec{X_i}}{N}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R = (\frac{\sum_{i=1}^N{(\vec{X_i} - \vec{X_0})}^2}{N})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D = (\frac{\sum_{i=1}^N\sum_{j=1}^N{(\vec{X_i} - \vec{X_j})}^2}{N(N-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; - это среднее расстояние от каждой точки до центроида. &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; - это среднее расстояние между парами в кластере. То есть по сути это две альтернативные метрики плотности кластера вокруг центроида.&lt;br /&gt;
&lt;br /&gt;
Для измерения близости друг к другу двух кластеров вводятся следующие метрики.&lt;br /&gt;
&lt;br /&gt;
Пусть даны центроиды двух кластеров &amp;lt;math&amp;gt;\vec{X_{01}}&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\vec{X_{02}}&amp;lt;/math&amp;gt;.&lt;br /&gt;
Евклидова метрика &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt; и метрика Манхэттена &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt; между двумя кластерами определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_0 = ((\vec{X_{01}}-\vec{X_{02}})^2)^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_1 = |\vec{X_{01}}-\vec{X_{02}}| = \sum_{i=1}^d |{\vec{X_{01}}}^{(i)}-{\vec{X_{02}}}^{(i)}| &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть имеются два кластера, содержащих соответственно  &amp;lt;math&amp;gt;N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_2&amp;lt;/math&amp;gt; точек размерности &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt;{\vec{X_i}}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i= 1,2, ...,N_1&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;{\vec{X_j}}&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;j= N_1+1,N1+2, ...,N_1+N_2&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Среднее расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &#039;&#039;&#039;среднее внутрикластерное расстояние&#039;&#039;&#039; &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &#039;&#039;&#039;дисперсия&#039;&#039;&#039; &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; для двух кластеров определяются следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;D_2 = (\frac{\sum_{i=1}^{N_1}\sum_{j=N_1+1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{N_1N_2})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;D_3 = (\frac{\sum_{i=1}^{N_1+N_2}\sum_{j=1}^{N_1+N_2}{(\vec{X_i} - \vec{X_j})}^2}{(N_1+N_2)(N_1+N_2-1)})^{1/2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;D_4 = \sum_{k=1}^{N_1+N_2}(\vec{X_k} - \frac{\sum_{i=1}^{N_1+N_2}\vec{X_i}}{N_1+N_2})^2 - \sum_{i=1}^{N_1}(\vec{X_i} - \frac{\sum_{i=1}^{N_1}\vec{X_i}}{N_1})^2 - \sum_{j=N_1+1}^{N_1+N_2}(\vec{X_j} - \frac{\sum_{i=N_1+1}^{N_1+N_2}\vec{X_i}}{N_2})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt; относятся к отдельным кластерам, а &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt; - к объединению двух кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Кластерные элементы и кластерное дерево ===&lt;br /&gt;
&lt;br /&gt;
В основе концепции алгоритма BIRCH лежат понятия &#039;&#039;&#039;кластерного элемента&#039;&#039;&#039; &#039;&#039;&#039;кластерного дерева (CF Tree)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Кластерный элемент ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; Пусть в кластере содержатся  &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; точек размерности  &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;:&amp;lt;math&amp;gt;\vec{X_i}&amp;lt;/math&amp;gt;, где  &amp;lt;math&amp;gt;i=1,2,...,N&amp;lt;/math&amp;gt;. &lt;br /&gt;
&#039;&#039;&#039;Кластерный элемент (CF)&#039;&#039;&#039; - тройка чисел, характеризующая информацию о кластере: &lt;br /&gt;
&amp;lt;math&amp;gt;CF = (N, \vec{LS}, SS)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; - количество элементов входных данных, содержащихся в кластере, &amp;lt;math&amp;gt;\vec{LS}&amp;lt;/math&amp;gt; - линейная сумма входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}\vec{X_i}&amp;lt;/math&amp;gt;), &amp;lt;math&amp;gt;SS&amp;lt;/math&amp;gt; - сумма квадратов входных данных (т.е. &amp;lt;math&amp;gt;\sum_{i=1}^{N}{\vec{X_i}}^2&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема&#039;&#039;&#039; Пусть &amp;lt;math&amp;gt;CF_1 = (N_1, \vec{LS_1}, SS_1)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;CF_2 = (N_1, \vec{LS_2}, SS_2)&amp;lt;/math&amp;gt; - CF векторы двух непересекающихся кластеров. Тогда при их объединении образуется кластер со следующим CF вектором: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;CF = CF_1 + CF_2 = (N_1+N_2, \vec{LS_1}+\vec{LS_2}, SS_1+SS_2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Из указанных выше определения и теоремы вытекает тот факт, что при объединении кластеров их CF вектор может вычисляться инкрементно и точно. &lt;br /&gt;
Легко показать, что вычислить величины &amp;lt;math&amp;gt;\vec{X_0}&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;R&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_3&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D_4&amp;lt;/math&amp;gt;, как и обычные метрики, также не составит труда.&lt;br /&gt;
&lt;br /&gt;
Таким образом, в данном случае информацией о кластере является не весь набор точек, а вектор CF. Хранение одного только вектора может показаться неэффективным, но этого вполне достаточно для оперирования всеми необходимыми метриками, на основе которых принимаются решения в алгоритме BIRCH.&lt;br /&gt;
&lt;br /&gt;
==== Кластерное дерево ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Определение.&#039;&#039; &#039;&#039;&#039;Кластерное дерево (CF Tree)&#039;&#039;&#039; - это взвешенно сбалансированное дерево с двумя параметрами: &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; - коэффициент разветвления, &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; - пороговая величина. Каждый нелистьевой узел дерева имеет не более чем &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt; вхождений узлов следующей формы: &amp;lt;math&amp;gt;[CF_i,child_i]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i=1,2,...,B&amp;lt;/math&amp;gt;, &#039;&#039;child&#039;&#039; - указатель на i-й дочерний узел, &amp;lt;math&amp;gt;CF_i&amp;lt;/math&amp;gt; - CF вектор соответствующего подкластера.&lt;br /&gt;
&lt;br /&gt;
Каждый листьевой узел имеет ссылку на два соседних узла (&#039;&#039;prev&#039;&#039; и &#039;&#039;next&#039;&#039;) для того, чтобы связать все узлы для эффективного сканирования.&lt;br /&gt;
Все листьевые узлы должны удовлетворять пороговому ограничению &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, т.е. диаметр (радиус) не должен превосходить &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
В процессе вставки новых данных CF дерево строится динамически. Оно использует вставку данных для кластеризации точно также как &amp;lt;math&amp;gt;B+&amp;lt;/math&amp;gt; дерево использует её для поиска.&lt;br /&gt;
CF дерево очень компактно, поскольку каждый листьевой узел - это не просто точка, а подкластер (который объединяет множество точек с учётом ограничения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
==== Операция вставки в &#039;&#039;&#039;CF&#039;&#039;&#039; дерево ====&lt;br /&gt;
&lt;br /&gt;
Опишем алгоритм вставки записи &amp;lt;math&amp;gt;Ent&amp;lt;/math&amp;gt; в CF дерево:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Определение подходящего листа&#039;&#039;: Начиная с корня, алгоритм рекурсивно спускается по CF дереву, выбирая &#039;&#039;&#039;ближайший&#039;&#039;&#039; дочерний узел в соответствии с выбранной метрикой &amp;lt;math&amp;gt;D0&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D1&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D2&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;D3&amp;lt;/math&amp;gt; или &amp;lt;math&amp;gt;D4&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Преобразование листа&#039;&#039;: Когда алгоритм достигает листьевого узла, он находит ближайшую листьевую запись, скажем, &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, а затем проверяет, может ли &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, &amp;quot;присоединить&amp;quot; &#039;&#039;Ent&#039;&#039;, без нарушения порогового условия. Если это так, то CF вектор для &amp;lt;math&amp;gt;L_1&amp;lt;/math&amp;gt;, изменяется с отражением этого факта. Если нет, то к листу добавляется новая запись для &#039;&#039;Ent&#039;&#039;. Если в листе есть место для этой новой записи, то шаг окончен, иначе листьевой узел должен &amp;quot;расщепиться&amp;quot;. Расщепление узла производится при помощи выбора наиболее удалённой друг от друга пары записей как источника и перераспределение оставшихся записей в соответствии с выбранным &amp;quot;критерием близости&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Преобразование пути к листу&#039;&#039;: После вставки &#039;&#039;Ent&#039;&#039; в лист мы должны обновить информацию о CF для каждой нелистьевой записи по дороге к листу. При отсутствии разделения это означает простое сложение CF векторов для отражения факта добавления &#039;&#039;Ent&#039;&#039;. Расщепление же листа требует вставки новой нелистьевой записи в родительский узел для описание только что созданного листа. Если у родителя есть место для этой записи, то нам нужно просто преобразовать CF векторы на всех более высоких уровнях. В общем случае, однако, нам также придётся расщепить родительский узел, и так далее до корня. Если расщеплён корень, то высота дерева увеличивается на единицу.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;Улучшение слияния&#039;&#039;: Разделение вызвано ограничением на размер узла, который не зависит от кластеризационных свойств данных. Если во входящем потоке присутствуют &amp;quot;искажённые&amp;quot; (из областей с низкой плотностью) данные, это может повлиять на качество кластеризации, а также уменьшить эффективность использования памяти. Дополнительный шаг алгоритма помогает решить эти проблемы: предположим, что произошло расщепление листа, и распространение этого процесса остановилось на некотором нелистьевом узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; can accomodate the additional entry resulting from the split. Теперь мы сканируем узел &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; для нахождения двух наиболее близких записей. Если это не пара, отвечающая разделению, мы пытаемся объединить их и поставить в соответствие два дочерних узла. Если в двух дочерних узлах записей больше, чем может содержать одна страница, мы снова разделяем результат объединения. В процессе перерасщепления, в том случае, если одна seed притягивает записей достаточно для того, чтобы заполнить таблицу, мы можем просто положить оставшиеся записи в другой ssed. В итоге, если мы объединяем подходящие записи на одной странице, м освобождаем в узле место для дальнейшего использования, создаём в узле &amp;lt;math&amp;gt;N_j&amp;lt;/math&amp;gt; место для дополнительной записи, тем самым увеличивая степень использования свободного пространства и откладывая дальнейшее расщепление; в ином случае мы улучшаем распределение записей в двух ближайших детях.&lt;br /&gt;
&lt;br /&gt;
Так как каждый узел в соответствии со своим размером может содержать ограниченное число записей, он всегда соответствует обычному кластеру. Иногда два подкластера, которые должны были быть в одном кластере, разделяются между узлами. В зависимости от порядка входных данных и степени их разброса, также возможна ситуация, когда два подкластера, которые не должны находиться в одном кластере, хранятся в одном узле. Эти нечастые, но нежелательные аномалии, спровоцированные размером страницы, можно исправить при помощи глобального (или полуглобального)агоритма, который собирает лист между узлами. Другой нежелательный случай, это ситуация, когда две одинаковые точки вставляются дважды, но в разное время, две их копии могут входить в отдельные листьевые записи. Или, другими словами, иногда в ситуации разброса входных данных, точка может входить в ту листьевую запись, в которую она не должна входить. Эту проблему можно решить при помощи дальнейшего улучшения данных.&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 представляет обзор алгоритма BIRCH. Главной задачей фазы 1 является сканирование всех данных и построение в памяти исходного CF дерева, используя заданное количество памяти. Это дерево старается отразить информацию о кластеризации данных настолько хорошо, насколько это позволяют ограничения по памяти. Тогда как плотно распределённые данные хорошо группируются в подкластеры, более разрозненные данные удаляются. После Фазы 1 вспомогательные вычисления в дальнейших фазах будут:&lt;br /&gt;
&lt;br /&gt;
1) быстрее, потому что (а) больше не нужны операции ввода-вывода, (b) проблема кластеризации начальных данных упрощается до проблемы кластеризации подкластеров в листьевых записях;&lt;br /&gt;
&lt;br /&gt;
2) точнее, потому что (а) большинство данных с низкой плотностью удалены, (b) оставшиеся данные распределены оптимально в соответствии с доступным количеством памяти&lt;br /&gt;
&lt;br /&gt;
3) менее чувствительны к порядку, потому что листьевые записи исходного дерева &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Фаза 1 ===&lt;br /&gt;
&lt;br /&gt;
Рисунок 2 детализирует Фазу 1. Она начинается с определения порогового значения, сканирования данных и добавления данных в дерево. Если память заканчивается до окончания сканирования данных, увеличивается пороговое значение и строится новое, меньшее CF дерево при помощи повторной вставки листьевых записей в старое дерево. После того как старые листьевые записи добавлены повторно, сканирование данных (и вставка в новое дерево) продолжается с той точки, где процесс был приостановлен.&lt;br /&gt;
&lt;br /&gt;
=== Уменьшаемость ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; - это CF дерево с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;. Его высота равна &amp;lt;math&amp;gt;h&amp;lt;/math&amp;gt;, а размер (количество узлов) равен &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Задавая &amp;lt;math&amp;gt;T_{i+1}\geq T_i&amp;lt;/math&amp;gt;, мы хотим использовать все листьевые записи &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; для построения нового CF дерева &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы размер &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; был не больше чем &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;. Далее описан алгоритм повторного построения, а также последовательность теорем уменьшаемости.&lt;br /&gt;
&lt;br /&gt;
Предположим, что внутри каждого CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; все соседние записи пронумерованы от &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;n_k-1&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n_k&amp;lt;/math&amp;gt; - это число записей в данном узле. Тогда &#039;&#039;&#039;путь&#039;&#039;&#039; из корневой записи (уровень 1) до листьевого узла (уровень &#039;&#039;h&#039;&#039;) уникально представляется вектором &amp;lt;math&amp;gt;(i_1, i_2, ..., i_{h-1})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i_j, j=1,...,h-1&amp;lt;/math&amp;gt; - это номера записей j-го уровня. Поэтому естественно принять, что путь &amp;lt;math&amp;gt;({i_1}^(1), {i_2}^(1), ..., {i_{h-1}}^(1))&amp;lt;/math&amp;gt; &#039;&#039;&#039;меньше&#039;&#039;&#039; пути &amp;lt;math&amp;gt;({i_1}^(2), {i_2}^(2), ..., {i_{h-1}}^(2))&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;{i_1}^{(1)}={i_1}^{(2)}, ..., {i_{j-1}}^{(1)}={i_{j-1}}^{(2)}&amp;lt;/math&amp;gt; и  &amp;lt;math&amp;gt;{i_j}^{(1)}&amp;lt;{i_j}^{(2)}&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;(0 \leq j \leq h-1) &amp;lt;/math&amp;gt;. Очевидно, что между понятиями листа и пути существует точное соответствие, поэтому в дальнейшем мы будет использовать эти понятия взаимозаменяемо.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм показан на рмсунке 3. Имея определение пути, указанное выше, он сканирует и освобождает старое дерево путь за путём и в то же время путь за путём создаёт новое дерево. Новое дерево начинается с NULL, а &amp;quot;OldCurrentPath&amp;quot; начинается с крайнего левого пути старого дерева. Для &amp;quot;OldCurrentPath&amp;quot; алгоритм работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
1) &#039;&#039;Создание соответствующей &amp;quot;NewCurrentPath&amp;quot; в новом дереве&#039;&#039;: узлы добавляются в новое дерево точно так же как и в старое, так что новое дерево никак не может стать больше старого&lt;br /&gt;
&lt;br /&gt;
2) &#039;&#039;Вставка листьевых записей &amp;quot;OldCurrentPath&amp;quot; в новое дерево&#039;&#039;: каждый лист в &amp;quot;OldCurrentPath&amp;quot; проверяется заново в соответствием с новым пороговым значением (???? АААА НАДОЕЛО)&lt;br /&gt;
&lt;br /&gt;
3) &#039;&#039;Освобождение места в &amp;quot;OldCurrentPath&amp;quot; и &amp;quot;NewCurrentPath&amp;quot;&#039;&#039;: после обработки всех листьев в &amp;quot;OldCurrentPath&amp;quot;, неиспользуемые узлы могут быть освобождены. Также может оказаться, что некоторые узлы &amp;quot;NewCurrentPath&amp;quot; пусты из-за того, что листьевые записи, которые изначально соответствовали этому пути, теперь &amp;quot;продвинуты вперёд&amp;quot; (???). В этом случае пустые узлы также необходимо удалить.&lt;br /&gt;
&lt;br /&gt;
4) &#039;&#039;&amp;quot;OldCurrentPath&amp;quot; устанавливается на следующий путь старого дерева (если такой существует), и шаги выше повторяются&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Теорема (уменьшаемости)&#039;&#039;&#039;: Пусть по указанному выше алгоритму CF дерево &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; построено из CF дерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; с пороговым значением &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; и пусть &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;S_{i+1}&amp;lt;/math&amp;gt; - их соответствующие размеры. Если &amp;lt;math&amp;gt;T_{i+1} \geq T_i&amp;lt;/math&amp;gt;, то &amp;lt;math&amp;gt;S_{i+1} \leq S_i&amp;lt;/math&amp;gt; и преобразованию &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;t_{i+1}&amp;lt;/math&amp;gt; необходимы как минимум h дополнительных страниц памяти, где h - это высота &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
=== Пороговые значения ===&lt;br /&gt;
&lt;br /&gt;
Правильный выбор порогового значения может значительно уменьшить количество перепостроений дерева. Так как начальное пороговое значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; увеличивается динамически, мы можем установить его значение слишком маленьким. Но если начальное значение &amp;lt;math&amp;gt;T_0&amp;lt;/math&amp;gt; слишком большое, мы получим менее детализированное CF дерево, чем это возможно при доступной памяти. BIRCH по умолчанию устанавливает значение, равное 0. Пользователь может его менять.&lt;br /&gt;
&lt;br /&gt;
Пусть значение &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt; оказалось слишком маленьким, и мы вышли за пределы памяти после сканирования &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt; точек и формирования &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; листьевых записей (каждая из которых удовлетворяет пороговому значению &amp;lt;math&amp;gt;T_i&amp;lt;/math&amp;gt;). Основываясь на части данных, которые мы просканировали и той части дерева, которое мы уже построили, необходимо оценить следующее пороговое значение &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt;. Эта оценка является сложной проблемой, а её решение выходит за пределы данной статьи. &lt;br /&gt;
&lt;br /&gt;
В настоящее время используется следующий подход:&lt;br /&gt;
&lt;br /&gt;
1) Мы пытаемся выбрать &amp;lt;math&amp;gt;T_{i+1}&amp;lt;/math&amp;gt; так, чтобы &amp;lt;math&amp;gt;N_{i+1}=Min(2N_i,N)&amp;lt;/math&amp;gt;. (????)&lt;br /&gt;
&lt;br /&gt;
2) Интуитивно мы хотим увеличить пороговое значение, основываясь на некоторой мере &#039;&#039;объёма&#039;&#039;. Существует два различных обозначений объём, которые мы используем, оценивая пороговую величину. Первое - средний объём, который определяется как &amp;lt;math&amp;gt;V_\alpha=r^d&amp;lt;/math&amp;gt;, где r - это средний радиус корневого кластера в CF дереве, а d - размерность пространства. Интуитивно понятно, что это мера места, занятого данными, проссканироанными до этого момента. &lt;br /&gt;
Следующее обозначение - упакованный объём, который определяется как &amp;lt;math&amp;gt;V_p = C_i*{T_i}^d&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; - это количество листьевых записей, а &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt; - максимальный объём листьевой записи. Интуитивно понятно, что это текущий объём, занятый листьевыми кластерами. Так как &amp;lt;math&amp;gt;C_i&amp;lt;/math&amp;gt; остаётся прежней, даже если мы выходим за пределы памяти (так как мы работаем с фиксированным объёмом памяти), то мы можем приблизить &amp;lt;math&amp;gt;V_p&amp;lt;/math&amp;gt; при помощи &amp;lt;math&amp;gt;{T_i}^d&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы делаем предположение, что &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; растёт с числом точек &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;. Зная &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;N_i&amp;lt;/math&amp;gt;, мы можем оценить &amp;lt;math&amp;gt;r_{i+1}&amp;lt;/math&amp;gt;, используя метод наименьших квадратов (что за линейная регрессия??). &lt;br /&gt;
&lt;br /&gt;
Определим коэффициент расширения &amp;lt;math&amp;gt;f = Max(1.0, \frac{r_{i+1}}{r_i}&amp;lt;/math&amp;gt;, и используем это как эвристическую меру  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&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;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Достоинства алгоритма ===&lt;br /&gt;
По сравнению с предыдущими методами BIRCH обладает следующими достоинствами:&lt;br /&gt;
&lt;br /&gt;
1. BIRCH является локальным алгоритмом, то есть каждое решение о каждом элементе кластера принимается без повторного сканирования данных или уже существующих кластеров. Используются только метрики, отражающие близость элементов друг к другу.&lt;br /&gt;
&lt;br /&gt;
2. BIRCH использует факт неравномерного распределения данных в пространстве и поэтому не все данные рассматриваются как одинаково важные для построения кластера. Области с большой плотностью обрабатываются как единый кластер. Данные в более разреженных областях могут удаляться (опционально).&lt;br /&gt;
&lt;br /&gt;
3. BIRCH использует всю доступную память для получения наилучших из возможных подкластеров, в то же время минимизируя затраты на операции ввода/вывода. Оптимизация процесса кластеризации достигается за счет использования взвешенно-сбалансированного дерева. При этом время исполнения линейно.&lt;br /&gt;
&lt;br /&gt;
4. BIRCH не требует всего набора данных заранее (при этом просматривает его всего один раз).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
&lt;br /&gt;
[1] Википедия&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Lineprinter&amp;diff=12120</id>
		<title>Обсуждение участника:Lineprinter</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:Lineprinter&amp;diff=12120"/>
		<updated>2016-10-15T21:12:25Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Перенос ==&lt;br /&gt;
Статья: [[Участник:Бобцов Борис/Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки]]&lt;br /&gt;
Выполняет: [[Участник:Бобцов Борис| Бобцов Борис]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Кластеризация сетями Кохонена]]&lt;br /&gt;
Выполняют: [[Участник:Kravtsovkirill| Кравцов Кирилл]] и [[Участник:Emaksimov| Максимов Егор]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Нахождение собственных чисел квадратной матрицы методом QR разложения (2)]]&lt;br /&gt;
Выполняют: Баев Олег и Шевелев Александр&lt;br /&gt;
&lt;br /&gt;
Статья: [[Стабилизированный метод биспоряженных градиентов (BiCGSTAB)]]&lt;br /&gt;
Выполняют: Гаврилов Алексей и Новиков Александр&lt;br /&gt;
&lt;br /&gt;
Статья: [[Участники: Бобошко А., Юмакаева А./Решение начальной задачи Коши для системы ОДУ методом Рунге-Кутта 4-го порядка]];&lt;br /&gt;
Выполняют: Бобошко Алексей и Юмакаева Алина&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм кластеризации, основанный на сетях Кохоннена]];&lt;br /&gt;
Выполняют:  Логвиненко Александра и Адиев Тохтар&lt;br /&gt;
&lt;br /&gt;
Статья: [[Ортогонализация Грама-Шмидта]];&lt;br /&gt;
Выполняют: [[Участник:KibAndrey| Кибанов Андрей]] и Аджиева Татьяна&lt;br /&gt;
&lt;br /&gt;
Статья: [[Самоорганизующиеся карты Кохонена]];&lt;br /&gt;
Выполняет: [[Участник:Anton goy| Гой Антон]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[ЕМ-алгоритм_(Тематическое_моделирование)]];&lt;br /&gt;
Выполняют: Мурат Апишев и Андрей Заночкин&lt;br /&gt;
&lt;br /&gt;
Статья:[[Алгоритм_Ланцоша_с_полной_переортогонализацией]];&lt;br /&gt;
Выполняет:[[Участник:Sfedotov| Федотов С.А.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм_k-средних]]&lt;br /&gt;
Выполняют: [[Участник:Error2407|Богомазов Евгений]], [[Участник:Илья_Егоров|Егоров Илья]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм k-means]]&lt;br /&gt;
Выполняют: [[Участник:Бротиковская Данута|Данута Бротиковская]] и [[Участник:DennZo1993|Денис Зобнин]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Partitioning Around Medoids (Алгоритм)]]&lt;br /&gt;
Выполняют: [[Участник:Denemmy| Галеев Данил]] и [[Участник:Ivan.Z| Запутляев Иван]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Нечеткий_алгоритм_С_средних]]&lt;br /&gt;
Выполняют: [[Участник:Demon smd|Д.А.Гуськов]], [[Участник:marina abramenkova|М.А.Абраменкова]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Решение_задачи_Коши_для_системы_ОДУ_методом_Рунге-Кутты_4_порядка]];&lt;br /&gt;
Выполняют: [[Участник:Алимов_Дамир_Алиевич|Алимов Дамир]] и [[Участник:Anlesnichiy|Антон Лесничий]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Строгий_алгоритм_С_средних_(Hard_C-Means,_HCM)]];&lt;br /&gt;
Выполняют: [[Участник:Светлана_Лукьяненко|Лукьяненко Светлана]] и [[Участник:Юрий_Комаров|Комаров Юрий]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм кластеризации, основанный на минимальном остовном дереве]];&lt;br /&gt;
Выполняет: [[Участник:Astandrik | Стандрик Антон Сергеевич]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Умножение разреженной матрицы на вектор]];&lt;br /&gt;
Выполняет: [[Участник:Lexaloris | Новоселов Алексей]], Выполняет: [[Участник:kochet|П.А. Кочетков]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Нахождение_собственных_чисел_квадратной_матрицы_методом_QR_разложения_(3)|Нахождение собственных чисел квадратной матрицы методом QR разложения (3)]];&lt;br /&gt;
Выполняют: [[Участник:Смирнова_Александра|Смирнова А.С.]], [[Участник:Александра_Киямова|Киямова А.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод_Якоби_вычисления_сингулярных_чисел_и_векторов]];&lt;br /&gt;
Выполняют: [[Участница:Почернина_Елена| Почернина Елена]] и [[Участница:Светлана|Костюкова Светлана]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод_Ньютона_для_решения_систем_нелинейных_уравнений(2)]];&lt;br /&gt;
Выполняют: [[Участник:Oleggium|Гирняк О.Р.]], [[Участник:Dimx19|Васильков Д.А.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм_кластеризации_с_использованием_представлений]];&lt;br /&gt;
Выполняют: [[Участник:Cookie|Шатков С.А.]], [[Участница:JuliaA|Антохина Ю.А.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Быстрое_преобразование_Фурье_(FFT)|Быстрое преобразование Фурье (FFT)]];&lt;br /&gt;
Выполняют: [[Участник:Victoria_Stepanischeva|Степанищева Виктория]] и [[Участник:Igor_Munkin|Мунькин Игорь]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Быстрое_дискретное_преобразование_Фурье|Быстрое_дискретное_преобразование_Фурье]];&lt;br /&gt;
Выполняют: [[Участник:ivanov.kir.m | К.М.Иванов]], [[Участник:Pumpkin | А.C.Сапин]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[Алгоритм_k_средних]]&lt;br /&gt;
Выполняют: [[Участник:Parkhomenko|Пархоменко Павел]], [[Участник:ivan.mashonskiy|Машонский Иван]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[EM-алгоритм_кластеризации]]&lt;br /&gt;
Выполняет: [[Участник:Noite|Зинченко Дмитрий]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[Алгоритм_k_means]]&lt;br /&gt;
Выполняют: [[Участник:IanaV| Валуйская Яна]], [[Участник:GlotovES| Глотов Евгений]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод Якоби вычисления собственных значений симметричной матрицы ЗП |Метод Якоби вычисления собственных значений симметричной матрицы ЗП]];&lt;br /&gt;
Выполняют: [[Участник:Зиновьев Владимир|Зиновьев В.С.]], [[Участник:Пронин Андрей|Пронин А.М.]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[Алгоритм_кластеризации,_основанный_на_минимальном_покрывающем_дереве]]&lt;br /&gt;
Выполняет: [[Участник:Kanast74|Дмитриева Анастасия]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[Нахождение_собственных_чисел_квадратной_матрицы_методом_QR_разложения_(4)]]&lt;br /&gt;
Выполняют: [[Участник:F-morozov|Морозов Ф. В.]], [[Участник:Nataliya|Пащенко Н. Ф.]]&lt;br /&gt;
&lt;br /&gt;
Статья:[[Хранение_ненулевых_элементов_разреженных_матриц._Умножение_разреженной_матрицы_на_вектор]];&lt;br /&gt;
Выполняют: [[Участник:Trrufina|Третьякова Р.М.]] и [[Участник:Екатерина_Буторина|Буторина Е.В.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм_кластеризации_с_использованием_представлений2]];&lt;br /&gt;
Выполняет: [[Участник:Лукьянова Анна|Лукьянова А.Я.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод Якоби вычисления собственных значений симметричной матрицы]];&lt;br /&gt;
Выполняют: [[Участник: Galkina|Галкина А.С.]], [[Участник: Игорь|Плахов И.А.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод рекурсивной координатной бисекции]];&lt;br /&gt;
Выполняют: [[Участник: Obirvalger|Гордеев Михаил]], [[Участник: KolmakovEA|Колмаков Евгений]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Итерационный метод решения системы линейных алгебраических уравнений GMRES (обобщенный метод минимальных невязок)]];&lt;br /&gt;
Выполняют: [[Участник: Эльвира Ахиярова|Ахиярова Эльвира]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Хранение ненулевых элементов разреженной матрицы. Умножение разреженной матрицы на вектор]];&lt;br /&gt;
Выполняют: [[Участник: Janyell|Сычева Евгения]], [[Участник: Ahahalin|Хахалин Анатолий]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Построение матрицы Адамара произвольного размера]];&lt;br /&gt;
Выполняют: [[Участник: Бугаков Юрий|Бугаков Юрий]], Кужамалиев Ернур&lt;br /&gt;
&lt;br /&gt;
Статья: [[Вычисление определенного интеграла с использованием адаптивно сгущающейся сетки (1)]]&lt;br /&gt;
Выполняют: [[Участница:Sannikovats| Санникова Татьяна Сергеевна]], [[Участник:Plukshin| Лукшин Петр Андреевич]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм кластеризации, основанный на построении каркаса]];&lt;br /&gt;
Выполняют: [[Участник:SenderovichNikita| Сендерович Никита]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Алгоритм кластеризации, основанный на максимизации ожидания]];&lt;br /&gt;
Выполняют: Готман Мария, Лукашкина Юлия&lt;br /&gt;
&lt;br /&gt;
Статья: [[Partitioning_Around_Medoids_(PAM)]]&lt;br /&gt;
Выполняют: [[Участник:Avasilenko|А.Э.Василенко]], [[Участник:Anastasia|А.В.Тузикова]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Нечеткий алгоритм С-средних (Fuzzy C-means)]]&lt;br /&gt;
Выполняют: [[Участник:Nikmedoed|Н.А. Муромцев]], [[Участник:illusive_mike|М.С. Дворецкий]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Нечеткий алгоритм C средних]]&lt;br /&gt;
Выполняют: [[Участник:Gkhazeeva|Гелана Хазеева]], [[Участник:Yushin|Павел Юшин]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Плотностный алгоритм кластеризации DBSCAN]]&lt;br /&gt;
Выполняют: [[Участник:Elena777mc|Малахова Е.С.]], [[Участник:Жаннат_Сагиолданова|Сагиолданова Ж.]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Кластеризация Partitioning Around Medoids (PAM)]]&lt;br /&gt;
Выполняют:[[ Участник:Тодуа Антон| Тодуа Антон]], [[Участник:Гусева Юлия| Гусева Юлия]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Участник:Бугаков Юрий (613 группа), Кужамалиев Ернур (601 группа)/Построение матрицы Адамара произвольной размерности]]&lt;br /&gt;
Выполняют:[[ Участник:Бугаков Юрий| Бугаков Юрий]], [[Участник:Кужамалиев Ернур| Кужамалиев Ернур]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Участник:Nikita/Построение_матрицы_Адамара|Построение матрицы Адамара]]&lt;br /&gt;
Выполняют: [[Участник:Nikita|Иванов Никита]], [[Участник:Tsyganov Nikita|Цыганов Никита]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[Метод Ньютона для решения систем нелинейных уравнений]]&lt;br /&gt;
Выполняют: [[Участник:Александр Чернышев|Александр Чернышев]], [[Участник:Захаров Никита|Захаров Никита]]&lt;br /&gt;
&lt;br /&gt;
Статья: [[BIRCH|Сбалансированный итеративный алгоритм редукции и кластеризации с использованием иерархий&lt;br /&gt;
(BIRCH)]]&lt;br /&gt;
Выполняют: [[Участник:Светлана Морозова|Морозова Светлана]], [[Участник:Smirnov.maxim|Смирнов Максим]]&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</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:Smirnov.maxim&amp;diff=12117</id>
		<title>Участник:Smirnov.maxim</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:Smirnov.maxim&amp;diff=12117"/>
		<updated>2016-10-15T21:11:20Z</updated>

		<summary type="html">&lt;p&gt;Smirnov.maxim: Новая страница: «Смирнов Максим Евгеньевич ВМК, группа 618/2»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Смирнов Максим Евгеньевич&lt;br /&gt;
ВМК, группа 618/2&lt;/div&gt;</summary>
		<author><name>Smirnov.maxim</name></author>
	</entry>
</feed>