<?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=%D0%98%D0%BB%D1%8C%D1%8F+%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2</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=%D0%98%D0%BB%D1%8C%D1%8F+%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2"/>
	<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/%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2"/>
	<updated>2026-10-22T20:04:10Z</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20872</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20872"/>
		<updated>2016-12-13T19:15:28Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
{{Assignment|Zhum|Konshin}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&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; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = {\rm random} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&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;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &amp;quot;Суммирование векторов&amp;quot; и &amp;quot;Деление вектора на скаляр&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &amp;lt;math&amp;gt;k \times n &amp;lt;/math&amp;gt; раз производится макрооперация &amp;quot;Вычисление расстояния между векторами&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; раз производится макрооперация &amp;quot;Поиск минимума в векторе&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &amp;lt;math&amp;gt;n - k&amp;lt;/math&amp;gt; раз производится макрооперация &amp;quot;Суммирование векторов&amp;quot; и &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; раз — &amp;quot;Деление вектора на скаляр&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; раз произвести макрооперацию &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;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Рисунок 1. Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Рисунок 2. Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Рисунок 3. Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — положительное число, т. е. &amp;lt;math&amp;gt;k &amp;gt; 0&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;n \times d + 1&amp;lt;/math&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;math&amp;gt;2 \times n&amp;lt;/math&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений воспользоваться только OpenMP без MPI.&lt;br /&gt;
&lt;br /&gt;
Код собирался под gcc c опцией -fopenmp. В очереди задача не стояла, так как код считался на одном процессоре, hyperthreading не использовался.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 4 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Рисунок 4. Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Рисунок 5. Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20856</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20856"/>
		<updated>2016-12-13T17:10:34Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Рисунок 1. Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Рисунок 2. Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Рисунок 3. Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений воспользоваться только OpenMP без MPI.&lt;br /&gt;
&lt;br /&gt;
Код собирался под gcc c опцией -fopenmp. В очереди задача не стояла, так как код считался на одном процессоре, hyperthreading не использовался.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 4 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Рисунок 4. Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Рисунок 5. Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20855</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20855"/>
		<updated>2016-12-13T17:09:54Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Рисунок 1. Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Рисунок 2. Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Рисунок 3. Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений воспользоваться только OpenMP без MPI.&lt;br /&gt;
&lt;br /&gt;
Код собирался под gcc c опцией -fopenmp. В очереди задача не стояла, так как код считался на одном процессоре, hyperthreading не использовался.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 2 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Рисунок 4. Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Рисунок 5. Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20854</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20854"/>
		<updated>2016-12-13T17:08:09Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Рисунок 1. Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Рисунок 2. Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Рисунок 3. Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений воспользоваться только OpenMP без MPI.&lt;br /&gt;
&lt;br /&gt;
Код собирался под gcc c опцией -fopenmp. В очереди задача не стояла, так как код считался на одном процессоре, hyperthreading не использовался.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Рисунок 4. Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Рисунок 5. Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20853</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20853"/>
		<updated>2016-12-13T17:06:29Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений воспользоваться только OpenMP без MPI.&lt;br /&gt;
&lt;br /&gt;
Код собирался под gcc c опцией -fopenmp. В очереди задача не стояла, так как код считался на одном процессоре, hyperthreading не использовался.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20852</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20852"/>
		<updated>2016-12-13T17:05:05Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;{\rm maxiter}&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; {\rm iter} &amp;lt; {\rm maxiter} &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; {\rm inc}({\rm iter}), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(\log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений &#039;&#039;&#039;воспользоваться только OpenMP без MPI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20849</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20849"/>
		<updated>2016-12-13T16:53:01Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{\rm argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{\rm argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm dist}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm dist}_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;{\rm index}: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;{\rm index}_{i} =   \underset{j}{\rm argmin }~{\rm dist}_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, {\rm index}_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; {\rm dist} &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; {\rm dist}_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; {\rm dist}&amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;{\rm index}&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений &#039;&#039;&#039;воспользоваться только OpenMP без MPI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20848</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20848"/>
		<updated>2016-12-13T16:49:50Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{\rm argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений &#039;&#039;&#039;воспользоваться только OpenMP без MPI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20847</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=20847"/>
		<updated>2016-12-13T16:44:48Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n\times k\times d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n\times d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n\times k\times d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n\times k\times (d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n\times k\times d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n\times k\times (d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n\times (k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) \times d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k \times  d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n\times d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n\times k\times d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k\times d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k\times d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n\times d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений &#039;&#039;&#039;воспользоваться только OpenMP без MPI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17812</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17812"/>
		<updated>2016-11-16T20:19:24Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних.  Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Так как на каждой итерации число действий на единицу данных не велико и данные должны быть собраны вместе при перерасчете центроидов, было решено для ускорения вычислений &#039;&#039;&#039;воспользоваться только OpenMP без MPI&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17720</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17720"/>
		<updated>2016-11-16T14:57:14Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17719</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17719"/>
		<updated>2016-11-16T14:56:54Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз — &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска — размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T — это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; — при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; — при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17718</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17718"/>
		<updated>2016-11-16T14:55:04Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле &#039;&#039;Время вычисления на 1 потоке / Время вычисления на T потоках / T&#039;&#039;, где T -- это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17717</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17717"/>
		<updated>2016-11-16T14:54:16Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь видно, что время выполнения операций алгоритма плавно убывает по каждому из параметров, причем скорость убывания по параметру числа процессоров выше, чем в зависимоти от размера данных.&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Здесь построена эффективность перехода от последовательной реализации к параллельной. Рассчитывается она по формуле *Время вычисления на 1 потоке / Время вычисления на T потоках / T*, где T -- это число потоков. При вычислении на 1 процессоре она равна 100 % в силу используемой формулы, что и отражено на графике.&lt;br /&gt;
&lt;br /&gt;
Проведем оценки масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17713</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17713"/>
		<updated>2016-11-16T14:45:05Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Параллельная реализация была написана самостоятельно на языке C, [http://git.algowiki-project.org/iaegorov/Egorov-Bogomazov-k-means/tree/master ссылка на реализацию]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17709</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17709"/>
		<updated>2016-11-16T14:29:47Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета]. Реализация была написана самостоятельно на языке C.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17708</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17708"/>
		<updated>2016-11-16T14:28:23Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений в общем случае постепенно убывает. На малых данных она выходит на пик мощности, являющийся максимумом эффективности в исследуемых условиях, но затем возвращается к процессу убывания.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17469</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17469"/>
		<updated>2016-11-15T20:59:24Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По числу процессов&#039;&#039;&#039; - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По размеру задачи&#039;&#039;&#039; - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;По двум направлениям&#039;&#039;&#039; - при увеличении как размера данных, так и числа процессов по всей рассмотренной области значений эффективность продолжает убывать.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17467</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17467"/>
		<updated>2016-11-15T20:58:42Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна &amp;lt;math&amp;gt;87,5%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16.33 / 11.87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна &amp;lt;math&amp;gt;11,1\%&amp;lt;/math&amp;gt;.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16.33 / 7.6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
По числу процессов - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
По размеру задачи - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
По двум направлениям - при увеличении как размера данных, так и числа процессов по всей рассмотренной области значений эффективность продолжает убывать.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17466</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17466"/>
		<updated>2016-11-15T20:57:16Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность в точке достигается при переходе от 1 потока на 8 при минимальном размере данных, она равна 87,5%.&lt;br /&gt;
*	Усредненная максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений на всех рассмотренных потока снижается с 16,33 до 11.87 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 16,33 / 11,87 / 2 \approx 68,4\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность в точке достигается при переходе от 1 потока на 16 при размере данных 800000, она равна 11,1%.&lt;br /&gt;
*	Усредненная минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 16,33 до 7,6 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 16,33 / 7,6 / 16 \approx 14,9\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведены графики зависимости вычислительного времени алгоритма и его эффективности от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Efficiency.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение эффективности алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
Оценка масштабируемости:&lt;br /&gt;
&lt;br /&gt;
По числу процессов - при увеличении числа процессов эффективность уменьшается на всей области рассматриваемых значений, причем темп убывания замедляется с ростом числа процессов.&lt;br /&gt;
По размеру задачи - при увеличении размера задачи эффективность вычислений вначале кратковременно возрастает, но затем начинает относительно равномерно убывать на всей рассматриваемой области.&lt;br /&gt;
По двум направлениям - при увеличении как размера данных, так и числа процессов по всей рассмотренной области значений эффективность продолжает убывать возрастает при при удалении точек, соответствующих большому числу процессов и малому размеру задачи. Затем эффективность не слишком интенсивно убывает.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17336</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17336"/>
		<updated>2016-11-15T18:04:10Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность достигается при переходе с одного потока на два. Среднее время вычислений снижается с 50 до 32 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 50 / 32 / 2 \approx 78\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 50 до 20 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 50 / 20 / 16 \approx 16\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведен график вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17335</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17335"/>
		<updated>2016-11-15T18:02:26Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность достигается при переходе с одного потока на два.&lt;br /&gt;
Среднее время вычислений снижается с 50 до 32 секунд, поэтому формально эффективность &amp;lt;math&amp;gt;= 50 / 32 / 2 \approx 78\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 50 до 20 секунд, поэтому формально эффективность &amp;lt;math&amp;gt; = 50 / 20 / 16 \approx 16\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведен график вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17333</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17333"/>
		<updated>2016-11-15T18:02:06Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные:&lt;br /&gt;
&lt;br /&gt;
*	Максимальная эффективность достигается при переходе с одного потока на два.&lt;br /&gt;
Среднее время вычислений снижается с 50 до 32 секунд, поэтому формально эффективность = &amp;lt;math&amp;gt;50 / 32 / 2 \approx 78\%&amp;lt;/math&amp;gt;&lt;br /&gt;
*	Минимальная эффективность наблюдается при переходе с одного на максимальное рассматриваемое в эксперименте число потоков, равное 16. Время вычисления изменяется с 50 до 20 секунд, поэтому формально эффективность = &amp;lt;math&amp;gt;50 / 20 / 16 \approx 16\%&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ниже приведен график вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17323</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17323"/>
		<updated>2016-11-15T17:33:53Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
Ниже приведен график вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа процессоров:&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17241</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17241"/>
		<updated>2016-11-15T12:28:23Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики числа итераций и вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа процессоров&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Iterations.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение числа итераций алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17240</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17240"/>
		<updated>2016-11-15T12:27:50Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики числа итераций и вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа потоков&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Iterations.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение числа итераций алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17236</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17236"/>
		<updated>2016-11-15T12:23:41Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма ===&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних согласно предложенной [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики числа итераций и вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа потоков&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Iterations.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение числа итераций алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17235</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17235"/>
		<updated>2016-11-15T12:22:56Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних согласно предложенной [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики числа итераций и вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа потоков&lt;br /&gt;
&lt;br /&gt;
[[file:Egorov_Bogomazov_Iterations.jpg|thumb|center|700px|Рисунок 5. Параллельная реализация алгоритма k-средних. Изменение числа итераций алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
[[file:Egorov_Bogomazov_Time.jpg|thumb|center|700px|Рисунок 6. Параллельная реализация алгоритма k-средних. Изменение вычислительного времени алгоритма в зависимости от числа процессоров и размера исходных данных.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17234</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17234"/>
		<updated>2016-11-15T12:17:36Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних согласно предложенной [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [1 : 16] с увеличением в 2 раза;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
В результате проведённых экспериментов были получены следующие данные&lt;br /&gt;
&lt;br /&gt;
На следующих рисунках приведены графики числа итераций и вычислительного времени алгоритма в зависимости от изменяемых параметров запуска -- размера данных и числа потоков&lt;br /&gt;
&lt;br /&gt;
[[file:Масштабируемость Параллельной реализации метода Холецкого Производительность3.png|thumb|center|700px|Рисунок 8. Параллельная реализация метода Холецкого. Изменение производительности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
[[file:Холецкий масштабируемость эффективность2.png|thumb|center|700px|Рисунок 9. Параллельная реализация метода Холецкого. Изменение эффективности в зависимости от числа процессоров и размера матрицы.]]&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17214</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=17214"/>
		<updated>2016-11-15T10:48:13Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость реализации ===&lt;br /&gt;
&lt;br /&gt;
Проведём исследование масштабируемости параллельной реализации алгоритма k-средних согласно предложенной [[Scalability methodology|методике]]. Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского университета].&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых [[Глоссарий#Параметры запуска|параметров запуска]] реализации алгоритма: &lt;br /&gt;
&lt;br /&gt;
*	число процессоров [4 : 256] с шагом 4;&lt;br /&gt;
*	размер данных [100000 : 1600000] с увеличением в 2 раза.&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Выводы для классов архитектур ==&lt;br /&gt;
&lt;br /&gt;
== Существующие реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Бесплатный доступ ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Десктопные программы&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16655</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16655"/>
		<updated>2016-11-13T13:05:19Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных за одну итерацию.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16646</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16646"/>
		<updated>2016-11-13T12:35:40Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16645</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16645"/>
		<updated>2016-11-13T12:35:31Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{Assignment}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16644</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16644"/>
		<updated>2016-11-13T12:34:42Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt;    операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16643</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16643"/>
		<updated>2016-11-13T12:34:28Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt; операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16642</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16642"/>
		<updated>2016-11-13T12:34:17Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений,&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность &amp;lt;math&amp;gt; = \dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt; операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16641</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16641"/>
		<updated>2016-11-13T12:33:44Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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\cdot k\cdot d&amp;lt;/math&amp;gt; умножений,&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;n \cdot d + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность = &amp;lt;math&amp;gt;\dfrac{n \cdot k \cdot d}{n\cdot d + 1} = k&amp;lt;/math&amp;gt; операций на единицу переданных данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16640</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=16640"/>
		<updated>2016-11-13T12:29:36Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Свойства алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность = &amp;lt;math&amp;gt;\dfrac{n*k*d}{n*d} = k&amp;lt;/math&amp;gt; умножений к объёму данных&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения алгоритма&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15881</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15881"/>
		<updated>2016-11-03T11:41:28Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Оба автора в равной мере участвовали в написании, обсуждении и оформлении содержимого статьи. Допустимо считать вклад каждого равным 50%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Свойства и структура алгоритмов =&lt;br /&gt;
== Общее описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15880</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=15880"/>
		<updated>2016-11-03T11:36:22Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &amp;quot;[[U:Илья Егоров|Илья Егоров]] — [[U:Богомазов Евгений|Евгений Богомазов]]&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;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=14110</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=14110"/>
		<updated>2016-10-26T21:15:25Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: добавил пустые разделы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&gt;
&lt;br /&gt;
== Особенности реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== [[Локальность данных и вычислений]] ==&lt;br /&gt;
&lt;br /&gt;
== Возможные способы и особенности параллельной реализации алгоритма ==&lt;br /&gt;
&lt;br /&gt;
== Масштабируемость алгоритма и его реализации ==&lt;br /&gt;
&lt;br /&gt;
== Динамические характеристики и эффективность реализации алгоритма ==&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=13310</id>
		<title>Участник:Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2&amp;diff=13310"/>
		<updated>2016-10-21T07:22:00Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;студент ВМК, 619 группа&lt;br /&gt;
&lt;br /&gt;
почта: ilya.a.egorov@gmail.com&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=12056</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=12056"/>
		<updated>2016-10-15T20:58:23Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}} &lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
&lt;br /&gt;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=12054</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=12054"/>
		<updated>2016-10-15T20:58:09Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}} &lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S~|~\underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа &#039;&#039;&#039;2a)&#039;&#039;&#039;) и нахождения индекса минимального элемента в каждой строке (этап &#039;&#039;&#039;2b)&#039;&#039;&#039;). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Нахождение вектора индексов распределения по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе &#039;&#039;&#039;3)&#039;&#039;&#039; происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11994</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11994"/>
		<updated>2016-10-15T20:52:19Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S | \underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа 2a) и нахождения индекса минимального элемента в каждой строке (этап 2b). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Этап 2b]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Операция вычисления расстояния]]&lt;br /&gt;
&lt;br /&gt;
На этапе 3) происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Обновление центроидов]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11986</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11986"/>
		<updated>2016-10-15T20:51:30Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S | \underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа 2a) и нахождения индекса минимального элемента в каждой строке (этап 2b). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
На этапе 3) происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster.png|800px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11979</id>
		<title>Участник:Илья Егоров/Алгоритм k-средних</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:%D0%98%D0%BB%D1%8C%D1%8F_%D0%95%D0%B3%D0%BE%D1%80%D0%BE%D0%B2/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k-%D1%81%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D1%85&amp;diff=11979"/>
		<updated>2016-10-15T20:51:10Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{algorithm&lt;br /&gt;
| name              = Алгоритм k-средних (k-means)&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Страница создана группой &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;
Алгоритм кластеризации k-средних впервые был предложен в 1950-х годах математиками Гуго Штейнгаузом и Стюартом Ллойдом независимо друг от друга. Наибольшую популярность он получил после работы Маккуина.&lt;br /&gt;
&lt;br /&gt;
Алгоритм позволяет при заданном числе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; построить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров, расположенных на максимальном расстоянии друг от друга. Таким образом, наибольшей точности результат выполнения алгоритма достигает при полной осведомленности Пользователя о характере кластеризуемых объектов и, как следствие, при обладании максимально корректной информацией о числе кластеров.&lt;br /&gt;
&lt;br /&gt;
В общем случае выбор числа &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; может базироваться на любых значимых факторах, в том числе на результатах предшествующих исследований, теоретических соображениях или интуиции. &lt;br /&gt;
&lt;br /&gt;
== Математическое описание алгоритма ==&lt;br /&gt;
&#039;&#039;&#039;Исходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Совокупность &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;d&amp;lt;/b&amp;gt;-мерных векторов &amp;lt;math&amp;gt; X = \{x_1 \dots x_n\} , &amp;lt;/math&amp;gt; где  &amp;lt;math&amp;gt; x_i = \{x_{i1} \dots x_{id}\} &amp;lt;/math&amp;gt;&lt;br /&gt;
* Предполагаемое количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные:&#039;&#039;&#039;&lt;br /&gt;
* Разбиение X на множество &amp;lt;math&amp;gt; S = \{S_1 \dots S_k \}, \bigcup S_i = X, S_i \cap S_j = \emptyset, i \neq j &amp;lt;/math&amp;gt;&lt;br /&gt;
* k центров кластеров &amp;lt;math&amp;gt; \Mu = \{\mu_1 \dots \mu_k \} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; \mu_i = \{\mu_{i1} \dots \mu_{id} \} &amp;lt;/math&amp;gt; такие, что&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \begin{cases}\tilde{\mu_i} = \underset{y}{argmin } \sum_{x \in S_i} ||x-y||^2_E \\ \Mu = \underset{\tilde{\Mu}}{argmin } \sum_{i \in k} \sum_{x \in S_i} ||x-\tilde{\mu_i}||^2_E \end{cases} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Алгоритм:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) &amp;lt;math&amp;gt; \mu_{i} = random &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2) &amp;lt;math&amp;gt; S_i = \{x \in S | \underset{j}{argmin } ||x-\mu_j||_E = i\} i = 1 \dots k &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3) &amp;lt;math&amp;gt; \tilde{\mu_{i}} = E_{x \in S_i}(x) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Если для &amp;lt;math&amp;gt; \forall i:  \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; то алгоритм завершен, иначе &amp;lt;math&amp;gt; \mu_i = \tilde{\mu_i} &amp;lt;/math&amp;gt; и перейти на пункт 2)&lt;br /&gt;
&lt;br /&gt;
== Вычислительное ядро алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Вычислительным ядром алгоритма является второй этап, а точнее нахождение матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;. Для &#039;&#039;&#039;d&#039;&#039;&#039;-мерного вектора &amp;lt;math&amp;gt;a:&amp;lt;/math&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;||a||=\sqrt{\sum_{i=1\dots d} a_i^2}&amp;lt;/math&amp;gt;, поэтому заполнение одной ячейки такой матрицы потребует &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt;d-1&amp;lt;/math&amp;gt; операций сложения и одну операция вычисления квадратного корня. Но так как эти расстояния используются только для сравнения, а &#039;&#039;sqrt&#039;&#039; является монотонно возрастающей функцией, то ее можно не вычислять. Поэтому нахождения матрицы расстояний потребует всего &amp;lt;math&amp;gt;n*k*d&amp;lt;/math&amp;gt; операций умножений и &amp;lt;math&amp;gt;n*k*(d-1)&amp;lt;/math&amp;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;
*&#039;&#039;&#039;Суммирование векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Поиск минимума в векторе&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Сравнение векторов&#039;&#039;&#039;,&lt;br /&gt;
*&#039;&#039;&#039;Деление вектора на скаляр&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1)&#039;&#039;&#039; На шаге инициализации центроидов в общем случае (случайный выбор элементов) макроопераций не производится. Но так как правило определения количества кластеров &#039;&#039;&#039;k&#039;&#039;&#039; неоднозначно, то для некоторых вариантов макрооперации могут понадобиться. К примеру, существует класс стратегий поиска &#039;&#039;&#039;k&#039;&#039;&#039;, которые базируются на определении центра масс всех объектов, и для которых будут дополнительно выполняться макрооперации &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; При составлении матрицы расстояний &#039;&#039;&#039; k &amp;lt;math&amp;gt; \cdot &amp;lt;/math&amp;gt;  n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Вычисление расстояния между векторами&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; При нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;n&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Поиск минимума в векторе&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; При пересчете центроидов &#039;&#039;&#039;n - k&#039;&#039;&#039; раз производится макрооперация &#039;&#039;&#039;&amp;quot;Суммирование векторов&amp;quot;&#039;&#039;&#039; и &#039;&#039;&#039;k&#039;&#039;&#039; раз - &#039;&#039;&#039;&amp;quot;Деление вектора на скаляр&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Для проверки критерия останова требуется &#039;&#039;&#039;k&#039;&#039;&#039; раз произвести макрооперацию &#039;&#039;&#039;&amp;quot;Сравнение векторов&amp;quot;&#039;&#039;&#039; для сопоставления обновленных значений центроидов с уже имеющимися.&lt;br /&gt;
&lt;br /&gt;
== Схема реализации последовательного алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Последовательность шагов алгоритма следующая:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1) Инициализация центроидов &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter = 1 &amp;lt;/math&amp;gt;, задание максимального количество итераций &amp;lt;math&amp;gt;maxiter&amp;lt;/math&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2a) Нахождение матрицы расстояний &#039;&#039;&#039;&amp;lt;math&amp;gt;dist:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;dist_{ij} = \sum_{l = 1\dots d} (x_{il}-\mu_{jl})^2&amp;lt;/math&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &#039;&#039;&#039;2b) Нахождение вектора распределения объектов по кластерам &#039;&#039;&#039;&amp;lt;math&amp;gt;index: &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;index_{i} =   \underset{j}{argmin }~dist_{ij} &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3) Пересчет центроидов &#039;&#039;&#039;&amp;lt;math&amp;gt;\tilde{\Mu}:&amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
        &amp;lt;math&amp;gt;\tilde{\mu_{ij}} = \sum_{l \in S_i} \dfrac{x_{lj}}{|S_i|} &amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;S_i = \{l~|~l \in 1\dots n, index_l = i\}  &amp;lt;/math&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4) Проверка критерия останова:&#039;&#039;&#039;&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;Если&#039;&#039;&#039; &amp;lt;math&amp;gt; \exists i: \tilde{\mu_i} \neq \mu_i&amp;lt;/math&amp;gt;, &amp;lt;math&amp;gt; iter &amp;lt; maxiter &amp;lt;/math&amp;gt;,&lt;br /&gt;
    &lt;br /&gt;
        &#039;&#039;&#039;то&#039;&#039;&#039; &amp;lt;math&amp;gt; inc(iter), \Mu=\tilde{\Mu},&amp;lt;/math&amp;gt; &#039;&#039;&#039;GOTO 2.а.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Последовательная сложность алгоритма ==&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;1)&#039;&#039;&#039; Сложность инициализации в общем случае зависит от применяемого метода генерации/получения случайных чисел, но ей можно пренебречь&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2a)&#039;&#039;&#039; Вычисление матрицы расстояний требует &amp;lt;math&amp;gt; n*k*d &amp;lt;/math&amp;gt; операций умножения и &amp;lt;math&amp;gt; n*k*(d-1) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределения требует &amp;lt;math&amp;gt; n*(k-1) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;3)&#039;&#039;&#039; Для вычисления &amp;lt;math&amp;gt; \tilde{\Mu} &amp;lt;/math&amp;gt; требуется &amp;lt;math&amp;gt; (n - k + 1) * d &amp;lt;/math&amp;gt; операций сложения и &amp;lt;math&amp;gt; k * d &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
    &lt;br /&gt;
    &#039;&#039;&#039;4)&#039;&#039;&#039; Для критерия останова требуется &amp;lt;math&amp;gt; n*d &amp;lt;/math&amp;gt; сравнений&lt;br /&gt;
&lt;br /&gt;
Итого: так как максимальное количество итераций задается в алгоритме заранее и не зависит от входных данных, то количество итераций ограничено константой. Тогда сложность алгоритма:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций сложения/вычитания&lt;br /&gt;
* &amp;lt;math&amp;gt; O(n*k*d)&amp;lt;/math&amp;gt; операций умножения, &amp;lt;math&amp;gt; O(k*d) &amp;lt;/math&amp;gt; операций деления&lt;br /&gt;
&lt;br /&gt;
== Информационный граф ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим вычислительные этапы алгоритма k-means. Это распределение объектов по кластерам и перерасчет центроидов.&lt;br /&gt;
&lt;br /&gt;
Распределение объектов по кластерам состоит из нахождения матрицы расстояний между &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\Mu&amp;lt;/math&amp;gt; (этапа 2a) и нахождения индекса минимального элемента в каждой строке (этап 2b). Ниже приведен информационный граф данного этапа.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovInf.png |800px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим этап вычисления ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; матрицы более подробно. Он представляет из себя скалярное произведение d-мерных векторов &amp;lt;math&amp;gt; x_i &amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt; \mu_j &amp;lt;/math&amp;gt;. Ниже приведена граф для данной операции.&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovDist.png|600px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
На этапе 3) происходит суммирование всех &amp;lt;math&amp;gt; x_l &amp;lt;/math&amp;gt; с одинаковым значением индекса в промежуточные суммы. Одновременно происходит подсчет количество элементов с фиксированным индексом. Затем происходит деление промежуточных сумм на соответствующее количество элементов в новом кластере, благодаря чему удается получить обновленные центроиды &amp;lt;math&amp;gt; \tilde{\mu}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:EgorovBogomazovNewCluster|800px|thumb|center|Описание]]&lt;br /&gt;
&lt;br /&gt;
== Ресурс параллелизма алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Для получения общей картины достаточно определить, в том числе и с помощью информационного графа, каким ресурсом параллелизма обладает каждый из этапов алгоритма:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2a)&#039;&#039;&#039; Нахождение каждой ячейки матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt; может происходить полностью независимо, так как они находятся на одном ярусе. При рассмотрении операции вычисления значения конкретной ячейки &amp;lt;math&amp;gt; dist_{ij} &amp;lt;/math&amp;gt; можно заметить, что все операции умножения также независимы между собой, поэтому понадобится всего одно умножение. Конечный результат получается в результате суммирования всех слагаемых и достигается параллельно за &amp;lt;math&amp;gt; \log(d) &amp;lt;/math&amp;gt; бинарных операций сложения при помощи стандартного метода &#039;&#039;reduction&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2b)&#039;&#039;&#039; Нахождение вектора распределений заключается в нахождении минимального элемента в каждой строке матрицы &amp;lt;math&amp;gt; dist &amp;lt;/math&amp;gt;. При использовании &#039;&#039;reduction&#039;&#039; эту операцию можно выполнить за &amp;lt;math&amp;gt; \log(k) &amp;lt;/math&amp;gt; бинарных операций сравнения.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3)&#039;&#039;&#039; В случае, если существует методология быстрого разделения &#039;&#039;&#039;n&#039;&#039;&#039; объектов на &#039;&#039;&#039;k&#039;&#039;&#039; множеств при помощи вектора индексации (косвенной адресации), все &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; могут быть обработаны параллельно. В рамках каждого отдельного &amp;lt;math&amp;gt; \tilde{S_i} &amp;lt;/math&amp;gt; можно проводить распараллеливание дальше, так как &amp;lt;math&amp;gt; x_{lj} &amp;lt;/math&amp;gt; также не зависят друг от друга. Таким образом, вычисление всех слагаемых для всех &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за одно параллельное деление, а нахождение суммы всех этих слагаемых для каждого &amp;lt;math&amp;gt; \tilde{\mu_{ij}} &amp;lt;/math&amp;gt; может быть выполнено за &amp;lt;math&amp;gt; O(log(n)) &amp;lt;/math&amp;gt; в худшем случае (при вхождении почти всех объектов в один кластер).&lt;br /&gt;
&lt;br /&gt;
Если же такой методологии не существует, то узким местом становится процесс распределения на множества согласно вектору &amp;lt;math&amp;gt;index&amp;lt;/math&amp;gt;, который можно выполнить за &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций косвенных адресаций. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4)&#039;&#039;&#039; Все сравнения для критерия останова также независимы между собой и могут быть выполнены за одну операцию сравнения, а финальный результат может быть получен за одну операцию сложения при работе над общей памятью (к примеру, прибавление единицы при несовпадении в общую память и сравнение ее с 0 по завершению) или за &amp;lt;math&amp;gt;\log(k*d)&amp;lt;/math&amp;gt; сложений иначе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как количество итераций ограничено константой, то на сложность оно не влияет. В итоге, параллельная сложность алгоритма k-means такова:&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(n*d)) &amp;lt;/math&amp;gt; операций сложения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(\log(k)) &amp;lt;/math&amp;gt; операций сравнения&lt;br /&gt;
* &amp;lt;math&amp;gt; O(1) &amp;lt;/math&amp;gt; операций умножения и деления&lt;br /&gt;
&lt;br /&gt;
== Входные и выходные данные алгоритма ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Количество кластеров &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;n&amp;lt;/b&amp;gt; кластеризуемых элементов&lt;br /&gt;
&lt;br /&gt;
Дополнительные ограничения:&lt;br /&gt;
* &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt; — положительное число, т. е. &amp;lt;b&amp;gt;k &amp;gt; 0&amp;lt;/b&amp;gt;.&lt;br /&gt;
* Для кластеризуемых элементов определена метрика (расстояние между объектами)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём входных данных&#039;&#039;&#039;: &amp;lt;b&amp;gt;n &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; d + 1&amp;lt;/b&amp;gt; (кластеризуемые объекты в виде векторов и число &amp;lt;b&amp;gt;k&amp;lt;/b&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: Массив, в который записаны принадлежности каждого элемента кластеру (допустим вывод в другой эквивалентной более удобной структуре).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объём выходных данных&#039;&#039;&#039;:  Размер массива равен &amp;lt;b&amp;gt;2 &amp;lt;math&amp;gt;\cdot&amp;lt;/math&amp;gt; n&amp;lt;/b&amp;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;
Алгоритм эффективно работает только на небольших объемах данных.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Преимущества алгоритма&#039;&#039;&#039;&lt;br /&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;
* Нет проверки корректности выбора числа кластеров&lt;br /&gt;
* Алгоритм чувствителен к количеству кластеров&lt;br /&gt;
* Алгоритм чувствителен к выбору начальных элементов в качестве центроидов &lt;br /&gt;
* Алгоритм крайне чувствителен к выбросам по данным&lt;br /&gt;
* Медленная работа на больших объемах данных&lt;br /&gt;
&lt;br /&gt;
= ЧАСТЬ. Программная реализация алгоритма =&lt;br /&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;
* [http://www.cs.waikato.ac.nz/ml/weka/ Weka]&lt;br /&gt;
* [http://docs.orange.biolab.si/2/reference/rst/Orange.clustering.kmeans.html Orange]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Фреймворки для языков&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Python:&#039;&#039;&#039;&lt;br /&gt;
** [http://scikit-learn.org/ scikit-learn]&lt;br /&gt;
** [https://www.scipy.org/ SciPy]&lt;br /&gt;
* &#039;&#039;&#039;C++:&#039;&#039;&#039;&lt;br /&gt;
** [http://mlpack.org/ MLPACK]&lt;br /&gt;
** [http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_ml/py_kmeans/py_kmeans_opencv/py_kmeans_opencv.html OpenCV]&lt;br /&gt;
** [https://www.gnu.org/software/octave/ Octave] &lt;br /&gt;
* &#039;&#039;&#039;C#:&#039;&#039;&#039;  &lt;br /&gt;
** [http://accord-framework.net/docs/html/T_Accord_MachineLearning_KMeans.htm Accord.NET]&lt;br /&gt;
* &#039;&#039;&#039;Java:&#039;&#039;&#039;&lt;br /&gt;
** [http://elki.dbs.ifi.lmu.de ELKI]&lt;br /&gt;
** [https://mahout.apache.org Mahout]&lt;br /&gt;
* &#039;&#039;&#039;Lua&#039;&#039;&#039;&lt;br /&gt;
** [http://torch.ch Torch]&lt;br /&gt;
&lt;br /&gt;
Языки [https://www.r-bloggers.com/k-means-clustering-in-r/ R] и [http://juliastats.github.io Julia] содержат алгоритм k-means в базовой реализации.&lt;br /&gt;
&lt;br /&gt;
=== Платный доступ/лицензия  ===&lt;br /&gt;
&lt;br /&gt;
Существует целый перечень мощных статистических и математических пакетов для разных ОС:&lt;br /&gt;
* [http://www.mathworks.com/help/stats/kmeans.html?requestedDomain=www.mathworks.com MATLAB]&lt;br /&gt;
* [http://mathworld.wolfram.com/K-MeansClusteringAlgorithm.html Mathematica]&lt;br /&gt;
* [http://www.stata.com/features/cluster-analysis/ Stata]&lt;br /&gt;
* [https://support.sas.com/rnd/app/stat/procedures/fastclus.html SAS]&lt;br /&gt;
* [https://blogs.sap.com/2013/03/28/sap-hana-pal-k-means-algorithm-or-how-to-do-customer-segmentation-for-the-telecommunications-industry/ SAP HANA]&lt;br /&gt;
* [http://docs.rapidminer.com/studio/operators/modeling/segmentation/k_means.html RapidMiner]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Литература =&lt;br /&gt;
[1] Нейский И.М. Классификация и сравнение методов кластеризации http://it-claim.ru/Persons/Neyskiy/Article2_Neiskiy.pdf&lt;br /&gt;
&lt;br /&gt;
[2] https://ru.wikipedia.org/wiki/K-means&lt;br /&gt;
&lt;br /&gt;
[[en:Description of algorithm properties and structure]]&lt;/div&gt;</summary>
		<author><name>Илья Егоров</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovNewCluster.png&amp;diff=11942</id>
		<title>Файл:EgorovBogomazovNewCluster.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovNewCluster.png&amp;diff=11942"/>
		<updated>2016-10-15T20:47:06Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: Илья Егоров загрузил новую версию Файл:EgorovBogomazovNewCluster.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Илья Егоров</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovNewCluster.png&amp;diff=11896</id>
		<title>Файл:EgorovBogomazovNewCluster.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovNewCluster.png&amp;diff=11896"/>
		<updated>2016-10-15T20:42:40Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Илья Егоров</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovDist.png&amp;diff=11881</id>
		<title>Файл:EgorovBogomazovDist.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:EgorovBogomazovDist.png&amp;diff=11881"/>
		<updated>2016-10-15T20:41:22Z</updated>

		<summary type="html">&lt;p&gt;Илья Егоров: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Илья Егоров</name></author>
	</entry>
</feed>