<?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=GlotovES</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=GlotovES"/>
	<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/GlotovES"/>
	<updated>2026-10-22T21:40:45Z</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=20440</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=20440"/>
		<updated>2016-12-08T21:18:29Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&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(iknd)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt; nd &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;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper. Опубликован позже в IEEE Transactions on Information Theory 28 (1982): 129-137.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;nk&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{\rm init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{\rm init} = kd&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{\rm init} = d(n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{\rm distr} = knd&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{\rm distr} = kn(d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{\rm distr} = knd&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{\rm min}_{\rm distr} = n(k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{\rm update} = kd&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{\rm update} = d(n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{\rm k-means} = N^{+}_{\rm init} + i \cdot (N^{+}_{\rm distr} + N^{-}_{\rm distr} + N^{+}_{\rm update}) = d(n - k) + i \cdot (kn(d-1)+knd+d(n-k)) \thicksim O(iknd)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{\rm k-means} = N^{/}_{\rm init} + i \cdot (N^{*}_{\rm distr} + N^{/}_{\rm update}) = kd + i \cdot (knd+kd) \thicksim O(iknd)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(iknd)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;math&amp;gt;\rm Init&amp;lt;/math&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;math&amp;gt;\rm Distribute&amp;lt;/math&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;math&amp;gt;\rm Update&amp;lt;/math&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;math&amp;gt;\rm dist&amp;lt;/math&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;math&amp;gt;\rm min&amp;lt;/math&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;math&amp;gt;-&amp;lt;/math&amp;gt;), затем возведение в квадрат (вершины &amp;lt;math&amp;gt;\rm sqr&amp;lt;/math&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;math&amp;gt;+&amp;lt;/math&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;\rm sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;\rm size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;math&amp;gt;/&amp;lt;/math&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{\rm k-means} = i \cdot (N_{\rm distr} + N_{\rm update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{\rm distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{\rm update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{\rm distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{\rm distr} = O(\log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;\log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{\rm distr} = O(\log(kd))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{\rm update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{\rm update} \leq O(\log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{\rm k-means} \leq i \cdot (\log(kd) + \log(n)) \thicksim O(i \cdot \log(knd)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;nd&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(\log (kn))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(iknd) \over O(i \cdot \log(knd))} \thicksim O \bigg( {knd \over \log(knd)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(iknd) \over nd+n+1} \thicksim {O(ikd) \over d+1} \thicksim O(ik)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(i \cdot \log(knd)) \over nd+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского Государственного Университета имени М.В. Ломоносова]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На рисунках 5 и 6 соответственно представлены графики зависимости производительности и эффективности параллельной реализации k means от числа кластеров  и числа процессов.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. График зависимости производительности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
По рис. 5 можно отметить практически полное отсутствие роста производительности с увеличением числа процессов от 256 до 512 при минимальном размере задачи. Это связано с быстрым ростом накладных расходов по отношению к крайне низкому объёму вычислений. При росте размера задачи данный эффект пропадает, и при одновременном пропорциональном увеличении числа кластеров и числа процессов рост производительности становится близким к линейному. &lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. График зависимости эффективности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
Исследовалась [https://github.com/like-a-bauss/kmeans параллельная реализация алгоритма k means на MPI]. &lt;br /&gt;
&amp;lt;p&amp;gt;Были получены следующие оценки масштабируемости реализации алгоритма k means:&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;i&amp;gt;По числу процессов:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.02209&amp;lt;/math&amp;gt;. Следовательно, с ростом числа процессов эффективность уменьшается. На рис. 6 можно наблюдать плавное и равномерное снижение производительности по мере увеличения числа процессов при неизменном числе кластеров, что свидетельствует об относительно невысоком росте накладных расходов на передачу данных между процессами и преобладании объёма вычислений над объёмом пересылок данных по сети.&lt;br /&gt;
*&amp;lt;i&amp;gt;По размеру задачи:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;0.01252&amp;lt;/math&amp;gt;. Следовательно, с ростом размера задачи (числа кластеров) эффективность увеличивается. При этом объём пересылок данных по сети пропорционален &amp;lt;math&amp;gt;(n + k) \cdot p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - число входных векторов, &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число процессов) таким образом, поскольку &amp;lt;math&amp;gt;k &amp;lt;&amp;lt; n&amp;lt;/math&amp;gt;, рост накладных расходов с ростом числа кластеров при неизменном числе процессов и входных векторов представляет собой незначительную величину.&lt;br /&gt;
*&amp;lt;i&amp;gt;Общая оценка:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.00081&amp;lt;/math&amp;gt;. Таким образом, с ростом и размера задачи, и числа процессов эффективность уменьшается. Это связано с тем, что отношение объёма вычислений к объёму передаваемых данных изменяется пропорционально &amp;lt;math&amp;gt;{kn \over (n + k) \cdot p} \thicksim {k \over p}&amp;lt;/math&amp;gt;, что представляет собой невысокий коэффициент, но при этом позволяет параллельной реализации не деградировать до нулевой эффективности при значительном увеличении числа процессов.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:IanaV&amp;diff=19254</id>
		<title>Обсуждение участника:IanaV</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:IanaV&amp;diff=19254"/>
		<updated>2016-11-26T20:26:38Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;п. 2.4&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой&amp;quot; - вписан Вами? Тогда где эта реализация? Если нет, зачем это отдельно отмечать?&lt;br /&gt;
* К графикам нет внятных пояснений.&lt;br /&gt;
&lt;br /&gt;
Исправления:&lt;br /&gt;
* Ссылка на окончательный текст программы была вписана еще в прошлый раз. Цитата: &amp;quot;Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой: &amp;lt;b&amp;gt;[https://github.com/like-a-bauss/kmeans окончательный текст программы]&amp;lt;/b&amp;gt;.&amp;quot;. Выделила жирным ссылку, чтобы было видно.&lt;br /&gt;
* Добавлены пояснения.&lt;br /&gt;
&lt;br /&gt;
Вопросы:&lt;br /&gt;
* Эта программа последний раз изменялась несколько лет назад, судя по информации с сайта. Предложение у Вас сформулировано так, как если бы Вами в эту программу &amp;quot;вписан код на MPI, реализующий...&amp;quot;. Если это так, то укажите версию с Вашими правками. Если нет, зачем писать об этой особенности программы?&lt;br /&gt;
* Пояснения весьма скудные, практически повторяющие подписи. Требуется пояснить изменение поведения программы при изменении условий исходя из этих графиков.&lt;br /&gt;
&lt;br /&gt;
Исправления:&lt;br /&gt;
* Добавлены развёрнутые пояснения к графикам и коэффициентам масштабируемости, ссылки приведены в соответствие.&lt;/div&gt;</summary>
		<author><name>GlotovES</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:IanaV&amp;diff=19253</id>
		<title>Обсуждение участника:IanaV</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%83%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA%D0%B0:IanaV&amp;diff=19253"/>
		<updated>2016-11-26T20:26:20Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;п. 2.4&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой&amp;quot; - вписан Вами? Тогда где эта реализация? Если нет, зачем это отдельно отмечать?&lt;br /&gt;
* К графикам нет внятных пояснений.&lt;br /&gt;
&lt;br /&gt;
Исправления:&lt;br /&gt;
* Ссылка на окончательный текст программы была вписана еще в прошлый раз. Цитата: &amp;quot;Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой: &amp;lt;b&amp;gt;[https://github.com/like-a-bauss/kmeans окончательный текст программы]&amp;lt;/b&amp;gt;.&amp;quot;. Выделила жирным ссылку, чтобы было видно.&lt;br /&gt;
* Добавлены пояснения.&lt;br /&gt;
&lt;br /&gt;
Вопросы:&lt;br /&gt;
* Эта программа последний раз изменялась несколько лет назад, судя по информации с сайта. Предложение у Вас сформулировано так, как если бы Вами в эту программу &amp;quot;вписан код на MPI, реализующий...&amp;quot;. Если это так, то укажите версию с Вашими правками. Если нет, зачем писать об этой особенности программы?&lt;br /&gt;
* Пояснения весьма скудные, практически повторяющие подписи. Требуется пояснить изменение поведения программы при изменении условий исходя из этих графиков.&lt;br /&gt;
&lt;br /&gt;
Исправления:&lt;br /&gt;
Добавлены развёрнутые пояснения к графикам и коэффициентам масштабируемости, ссылки приведены в соответствие.&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19252</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19252"/>
		<updated>2016-11-26T20:21:30Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского Государственного Университета имени М.В. Ломоносова]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На рисунках 5 и 6 соответственно представлены графики зависимости производительности и эффективности параллельной реализации k means от числа кластеров  и числа процессов.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. График зависимости производительности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
По рис. 5 можно отметить практически полное отсутствие роста производительности с увеличением числа процессов от 256 до 512 при минимальном размере задачи. Это связано с быстрым ростом накладных расходов по отношению к крайне низкому объёму вычислений. При росте размера задачи данный эффект пропадает, и при одновременном пропорциональном увеличении числа кластеров и числа процессов рост производительности становится близким к линейному. &lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. График зависимости эффективности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
Исследовалась [https://github.com/like-a-bauss/kmeans параллельная реализация алгоритма k means].&lt;br /&gt;
&amp;lt;p&amp;gt;Были получены следующие оценки масштабируемости реализации алгоритма k means:&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;i&amp;gt;По числу процессов:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.02209&amp;lt;/math&amp;gt;. Следовательно, с ростом числа процессов эффективность уменьшается. На рис. 6 можно наблюдать плавное и равномерное снижение производительности по мере увеличения числа процессов при неизменном числе кластеров, что свидетельствует об относительно невысоком росте накладных расходов на передачу данных между процессами и преобладании объёма вычислений над объёмом пересылок данных по сети.&lt;br /&gt;
*&amp;lt;i&amp;gt;По размеру задачи:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;0.01252&amp;lt;/math&amp;gt;. Следовательно, с ростом размера задачи (числа кластеров) эффективность увеличивается. При этом объём пересылок данных по сети пропорционален &amp;lt;math&amp;gt;(n + k) * p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - число входных векторов, &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число процессов) таким образом, поскольку &amp;lt;math&amp;gt;k &amp;lt;&amp;lt; n&amp;lt;/math&amp;gt;, рост накладных расходов с ростом числа кластеров при неизменном числе процессов и входных векторов представляет собой незначительную величину.&lt;br /&gt;
*&amp;lt;i&amp;gt;Общая оценка:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.00081&amp;lt;/math&amp;gt;. Таким образом, с ростом и размера задачи, и числа процессов эффективность уменьшается. Это связано с тем, что отношение объёма вычислений к объёму передаваемых данных изменяется пропорционально &amp;lt;math&amp;gt;{n * k \over (n + k) * p} \thicksim {k \over p}&amp;lt;/math&amp;gt;, что преставляет собой невысокий коэффициент, но при этом позволяет параллельной реализации не деградировать до нулевой эффективности при значительном увеличении числа процессов.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19251</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19251"/>
		<updated>2016-11-26T20:18:50Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского Государственного Университета имени М.В. Ломоносова]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На рисунках 5 и 6 соответственно представлены графики зависимости производительности и эффективности параллельной реализации k means от числа кластеров  и числа процессов.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. График зависимости производительности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
Можно отметить практически полное отсутствие роста производительности с увеличением числа процессов от 256 до 512 при минимальном размере задачи. Это связано с быстрым ростом накладных расходов по отношению к крайне низкому объёму вычислений. При росте размера задачи данный эффект пропадает, и при одновременном пропорциональном увеличении числа кластеров и числа процессов рост производительности становится близким к линейному. &lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. График зависимости эффективности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
Исследовалась [https://github.com/like-a-bauss/kmeans параллельная реализация алгоритма k means].&lt;br /&gt;
&amp;lt;p&amp;gt;Были получены следующие оценки масштабируемости реализации алгоритма k means:&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;i&amp;gt;По числу процессов:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.02209&amp;lt;/math&amp;gt;. Следовательно, с ростом числа процессов эффективность уменьшается. На рис. 6 можно наблюдать плавное и равномерное снижение производительности по мере увеличения числа процессов при неизменном числе кластеров, что свидетельствует об относительно невысоком росте накладных расходов на передачу данных между процессами и преобладании объёма вычислений над объёмом пересылок данных по сети.&lt;br /&gt;
*&amp;lt;i&amp;gt;По размеру задачи:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;0.01252&amp;lt;/math&amp;gt;. Следовательно, с ростом размера задачи (числа кластеров) эффективность увеличивается. При этом объём пересылок данных по сети пропорционален &amp;lt;math&amp;gt;(n + k) * p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - число входных векторов, &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число процессов) таким образом, поскольку &amp;lt;math&amp;gt;k &amp;lt;&amp;lt; n&amp;lt;/math&amp;gt;, рост накладных расходов с ростом числа кластеров при неизменном числе процессов и входных векторов представляет собой незначительную величину.&lt;br /&gt;
*&amp;lt;i&amp;gt;Общая оценка:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.00081&amp;lt;/math&amp;gt;. Таким образом, с ростом и размера задачи, и числа процессов эффективность уменьшается. Это связано с тем, что отношение объёма вычислений к объёму передаваемых данных изменяется пропорционально &amp;lt;math&amp;gt;{n * k \over (n + k) * p} \thicksim {k \over p}&amp;lt;/math&amp;gt;, что преставляет собой невысокий коэффициент, но при этом позволяет параллельной реализации не деградировать до нулевой эффективности при значительном увеличении числа процессов.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19249</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=19249"/>
		<updated>2016-11-26T19:51:27Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Assignment}}&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; [http://parallel.ru/cluster Суперкомпьютерного комплекса Московского Государственного Университета имени М.В. Ломоносова]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На рисунках 5 и 6 соответственно представлены графики зависимости производительности и эффективности параллельной реализации k means от числа кластеров  и числа процессов.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. График зависимости производительности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. График зависимости эффективности параллельной реализации алгоритма от числа кластеров и числа процессов. ]]&lt;br /&gt;
Исследовалась [https://github.com/serban/kmeans параллельная реализация алгоритма k means]. Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой: &amp;lt;b&amp;gt;[https://github.com/like-a-bauss/kmeans окончательный текст программы]&amp;lt;/b&amp;gt;.&lt;br /&gt;
&amp;lt;p&amp;gt;Были получены следующие оценки масштабируемости реализации алгоритма k means:&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;i&amp;gt;По числу процессов:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.02209&amp;lt;/math&amp;gt;. Следовательно, с ростом числа процессов эффективность уменьшается. На рис. 6 можно наблюдать плавное и равномерное снижение производительности по мере увеличения числа процессов при неизменном числе кластеров, что свидетельствует об относительно невысоком росте накладных расходов на передачу данных между процессами и преобладании объёма вычислений над объёмом пересылок данных по сети.&lt;br /&gt;
*&amp;lt;i&amp;gt;По размеру задачи:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;0.01252&amp;lt;/math&amp;gt;. Следовательно, с ростом размера задачи (числа кластеров) эффективность увеличивается. При этом объём пересылок данных по сети пропорционален &amp;lt;math&amp;gt;(n + k) * p&amp;lt;/math&amp;gt; (где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; - число входных векторов, &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - число процессов) таким образом, поскольку &amp;lt;math&amp;gt;k &amp;lt;&amp;lt; n&amp;lt;/math&amp;gt;, рост накладных расходов с ростом числа кластеров при неизменном числе процессов и входных векторов представляет собой незначительную величину.&lt;br /&gt;
*&amp;lt;i&amp;gt;Общая оценка:&amp;lt;/i&amp;gt; &amp;lt;math&amp;gt;-0.00081&amp;lt;/math&amp;gt;. Таким образом, с ростом и размера задачи, и числа процессов эффективность уменьшается. Это связано с тем, что отношение объёма вычислений к объёму передаваемых данных изменяется пропорционально &amp;lt;math&amp;gt;{n * k \over (n + k) * p} \thicksim {k \over p}&amp;lt;/math&amp;gt;, что преставляет собой невысокий коэффициент, но при этом позволяет параллельной реализации не деградировать до нулевой эффективности при значительном увеличении числа процессов.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17174</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17174"/>
		<updated>2016-11-14T23:56:46Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации &amp;lt;b&amp;gt;k means&amp;lt;/b&amp;gt; в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
Исследовалась [https://github.com/serban/kmeans параллельная реализация алгоритма k means]. Для вычисления производительности в неё был вписан код на MPI, реализующий подсчёт числа операций с плавающей точкой.&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17140</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17140"/>
		<updated>2016-11-14T21:54:10Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации &amp;lt;b&amp;gt;k means&amp;lt;/b&amp;gt; в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
Исследовалась [https://github.com/serban/kmeans параллельная реализация алгоритма k means].&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17125</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17125"/>
		<updated>2016-11-14T20:29:10Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Набор данных для тестирования состоял из 946000 векторов размерности 2 (координаты на сфере)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Набор и границы значений изменяемых параметров запуска реализации алгоритма:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512];&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации &amp;lt;math&amp;gt;2,47%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 352 кластера с использованием 8 процессов;&lt;br /&gt;
* максимальная эффективность реализации &amp;lt;math&amp;gt;7,13%&amp;lt;/math&amp;gt; достигается при делении исходных данных на 128 кластеров с использованием 512 процессов.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации &amp;lt;b&amp;gt;k means&amp;lt;/b&amp;gt; в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
Исследовалась [https://github.com/serban/kmeans параллельная реализация алгоритма k means].&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17071</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17071"/>
		<updated>2016-11-14T16:32:03Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512] с шагом 8;&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации 2,47%;&lt;br /&gt;
* максимальная эффективность реализации 7,13%.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации &amp;lt;b&amp;gt;k means&amp;lt;/b&amp;gt; в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17069</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17069"/>
		<updated>2016-11-14T16:28:36Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512] с шагом 8;&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации 2,47%;&lt;br /&gt;
* максимальная эффективность реализации 7,13%.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации разложения Холецкого в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17058</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=17058"/>
		<updated>2016-11-14T15:52:21Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Исследование проводилось на суперкомпьютере &amp;quot;Ломоносов&amp;quot; Суперкомпьютерного комплекса МГУ им. М.В. Ломоносова.&lt;br /&gt;
&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессов (виртуальных ядер) [8 : 512] с шагом 8;&lt;br /&gt;
* число кластеров [128 : 384].&lt;br /&gt;
В результате проведённых экспериментов был получен следующий диапазон эффективности реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* минимальная эффективность реализации 2,47%;&lt;br /&gt;
* максимальная эффективность реализации 6,94%.&lt;br /&gt;
На следующих рисунках приведены графики производительности и эффективности выбранной реализации разложения Холецкого в зависимости от изменяемых параметров запуска.&lt;br /&gt;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 6. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=16089</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=16089"/>
		<updated>2016-11-07T21:39:31Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Масштабируемость реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; {{Assignment|Zhum}}&lt;br /&gt;
&lt;br /&gt;
{{level-a}}&lt;br /&gt;
Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм k-means является итерационным алгоритмом кластеризации. На каждой итерации происходит пересчет центра масс для каждого кластера, полученного на предыдущем шаге, затем исходные векторы заново распределяются по кластерам в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Таким образом, алгоритм в терминах макроопераций выглядит следующим образом:&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;p&amp;gt;Метод Forgy: центры масс &amp;lt;math&amp;gt;\mu_j^1, j = 1, ..., k&amp;lt;/math&amp;gt; выбираются случайным образом.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Метод случайного разбиения: вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; случайным образом распределяются по кластерам. Для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс кластера&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^1&amp;lt;/math&amp;gt;.&amp;lt;/p&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого вектора &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; k раз выполняется макрооперация &amp;quot;Расстояние между векторами&amp;quot; для нахождения расстояния между &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Затем для каждого вектора &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt; находится минимальное расстояние.&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге для каждого кластера выполняется макрооперация &amp;quot;Пересчет центра масс&amp;quot; для нахождения &amp;lt;math&amp;gt;\mu_j^{t+1}&amp;lt;/math&amp;gt;.&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому зачастую проводят несколько прогонов алгоритма с разными значениями &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;, чтобы подобрать оптимальный;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
[[file:kmeans_performance.jpg|thumb|center|720px|Рисунок 4. Параллельная реализация k means. Максимальная производительность. ]]&lt;br /&gt;
[[file:kmeans_efficiency.jpg|thumb|center|720px|Рисунок 5. Параллельная реализация k means. Максимальная эффективность. ]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11433</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11433"/>
		<updated>2016-10-15T19:30:07Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = k means&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n*k*d*i)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;O(log(n*k*d)*i)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;O \bigg( {n*k*d \over log(n*k*d)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n*d+1&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;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11373</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11373"/>
		<updated>2016-10-15T19:20:39Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: &amp;lt;p&amp;gt;Множество входных векторов можно равномерно разделить между параллельными вычислителями. Центры всех кластеров можно распространить на все вычислители (так как их заведомо меньше, чем число входных векторов). В таком случае на каждой итерации определение для каждого объекта ближайшего кластера представляет собой вычисление расстояния от каждого входного вектора, находящегося на вычислителе, до каждого кластера, и является является сбалансированной операцией. После данного этапа происходит пересчёт центров кластеров. Данная операция является несбалансированной в случаях, когда число  объектов в одном из кластеров значительно больше числа объектов в других кластерах, из-за чего один кластер занимает большое число вычислителей, а остальные занимают по одному или несколько вычислителей. В таком случае для данного кластера потребуется вычислить центр [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритмом нахождения частичной суммы элементов массива путем сдваивания]]. Данная операция представляет несбалансированность порядка &amp;lt;math&amp;gt;O(log (k*n))&amp;lt;/math&amp;gt;. После данного шага происходит сбалансированная операция рассылки центров кластеров на все вычислители.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;В идеальном случае параллелизации алгоритм не является сбалансированным, однако в реальных задачах, когда &amp;lt;math&amp;gt;n &amp;gt;&amp;gt; p&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; - количество вычислителей, эта несбалансированность сглаживается наличием объектов из каждого кластера на каждом вычислителе&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11029</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=11029"/>
		<updated>2016-10-15T18:07:06Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже (&amp;lt;i&amp;gt;рисунок 3&amp;lt;/i&amp;gt;). Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения количества элементов в нем (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;p&amp;gt;Последовательный алгоритм: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Параллельный алгоритм: &amp;lt;math&amp;gt;O(log(n*d*k)*i) \over n*d+n+1&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=10864</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=10864"/>
		<updated>2016-10-15T17:38:26Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
Вклад в основную часть работы (сбор и анализ данных) у авторов одинаков, четких разграничений по пунктам статьи сделать невозможно. Итоговое оформление статьи выполнила Валуйская Я.А.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x_i \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_j^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i, \mu_j^t))^2 , j = 1, ..., k; i = 1, ..., n&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;; &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Способы инициализации начальных данных:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Метод Forgy &amp;lt;br&amp;gt; Случайным образом выбираются &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; векторов из множества наблюдений &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Эти вектора используются в качестве центров масс кластеров &amp;lt;math&amp;gt;\mu_1, ..., \mu_k&amp;lt;/math&amp;gt;&lt;br /&gt;
# Метод случайного разбиения (Random Partition) &amp;lt;ref&amp;gt;[http://people.csail.mit.edu/tieu/notebook/kmeans/15_p600-hamerly.pdf Hamerly, G.; Elkan, C. (2002). &amp;quot;Alternatives to the k-means algorithm that find better clusterings&amp;quot;. Proceedings of the eleventh international conference on Information and knowledge management (CIKM).]&amp;lt;/ref&amp;gt; &amp;lt;br&amp;gt; Каждый вектор &amp;lt;math&amp;gt;x_i, i = 1, .., n&amp;lt;/math&amp;gt; случайным образом распределяется в кластер &amp;lt;math&amp;gt;S_j, j = 1, .., k&amp;lt;/math&amp;gt;, затем для каждого кластера вычисляется его центр масс &amp;lt;math&amp;gt;\mu_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
Существующие способы оптимизации алгоритма &amp;lt;ref&amp;gt;[http://link.springer.com/chapter/10.1007/3-540-45643-0_13  Phillips S. J. Acceleration of k-means and related clustering algorithms //Workshop on Algorithm Engineering and Experimentation. – Springer Berlin Heidelberg, 2002. – С. 166-177.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.187.3017&amp;amp;rep=rep1&amp;amp;type=pdf  Hamerly G. Making k-means Even Faster //SDM. – 2010. – С. 130-140.]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;[http://cseweb.ucsd.edu/~elkan/kmeansicml03.pdf  Elkan C. Using the triangle inequality to accelerate k-means //ICML. – 2003. – Т. 3. – С. 147-153.]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Подсчитаем количество операций для каждого шага алгоритма.&lt;br /&gt;
&lt;br /&gt;
# Инициализация:&lt;br /&gt;
#* Метод Forgy: &amp;lt;math&amp;gt;N_{init} = 0&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Метод случайного разбиения: &lt;br /&gt;
#** Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{init} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#** Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{init} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Распределение &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам на одной итерации:&lt;br /&gt;
#* Количество операций умножения: &amp;lt;math&amp;gt;N^{*}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = k * n * (d - 1)&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций вычитания: &amp;lt;math&amp;gt;N^{-}_{distr} = k * n * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций взятия минимума: &amp;lt;math&amp;gt;N^{min}_{distr} = n * (k - 1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Пересчет центра масс &amp;lt;math&amp;gt;\mu_i \in R^d&amp;lt;/math&amp;gt; для &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластеров на одной итерации:&lt;br /&gt;
#* Количество операций деления: &amp;lt;math&amp;gt;N^{/}_{update} = k * d&amp;lt;/math&amp;gt;;&lt;br /&gt;
#* Количество операций сложения: &amp;lt;math&amp;gt;N^{+}_{update} = d * (n - k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, в случае если алгоритм сошелся за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, получаем:&lt;br /&gt;
* Операций сложения/вычитания: &amp;lt;math&amp;gt;N^{+,-}_{k-means} = N^{+}_{init} + i*(N^{+}_{distr} + N^{-}_{distr} + N^{+}_{update}) = d * (n - k) + i*(k*n*(d-1)+k*n*d+d*(n-k)) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Операций умножения/деления: &amp;lt;math&amp;gt;N^{*,/}_{k-means} = N^{/}_{init} + i*(N^{*}_{distr} + N^{/}_{update}) = k * d + i*(k*n*d+k*d) \thicksim O(i*k*n*d)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, [[глоссарий#Последовательная сложность|&#039;&#039;последовательная сложность&#039;&#039;]] алгоритма k-means для &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;k&amp;lt;/math&amp;gt; кластеров за &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; итераций, требуемых для сходимости алгоритма:  &amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;O(i * n * k * d)&amp;lt;/math&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим информационный граф алгоритма k-means.&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 1&amp;lt;/i&amp;gt; представлена общая схема алгоритма k-means, согласно разделу [[#Схема реализации последовательного алгоритма|&amp;quot;Схема реализации последовательного алгоритма&amp;quot;]]. &lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Init&amp;lt;/i&amp;gt; - этап инициализации.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Distribute&amp;lt;/i&amp;gt; - этап распределения векторов по кластерам.&lt;br /&gt;
Вершина &amp;lt;i&amp;gt;Update&amp;lt;/i&amp;gt; - этап пересчета центров масс кластеров.&lt;br /&gt;
[[file:k-means-all.PNG|800px|thumb|center|Рисунок 1. Общая схема алгоритма k-means]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 2&amp;lt;/i&amp;gt; представлен информационный граф этапа распределения векторов по кластерам. На вход данному этапу подают множество векторов &amp;lt;math&amp;gt;x_1, x_2, ..., x_n&amp;lt;/math&amp;gt; из входных данных и множество центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, ..., \mu^t_k&amp;lt;/math&amp;gt;, полученных с шага инициализации или с предыдущей итерации. Для каждой пары векторов &amp;lt;math&amp;gt;x_i, \mu^t_j, i = 1, ..., n; j = 1,..., k&amp;lt;/math&amp;gt; считается расстояние между ними (вершина &amp;lt;i&amp;gt;dist&amp;lt;/i&amp;gt;). Информационный граф вычисления расстояния между двумя векторами рассмотрен ниже. Затем выполняется операция нахождения минимума (вершина &amp;lt;i&amp;gt;min&amp;lt;/i&amp;gt;), в результате которой каждому вектору &amp;lt;math&amp;gt;x_i, i = 1, ..., n&amp;lt;/math&amp;gt; приписывается метка &amp;lt;math&amp;gt;l^t_i&amp;lt;/math&amp;gt;, равная порядковому номеру кластера &amp;lt;math&amp;gt;S^t_j, j = 1 ..., k&amp;lt;/math&amp;gt;, которому принадлежит данный вектор: &amp;lt;math&amp;gt;x_i \in S^t_j&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-distribute.PNG|800px|thumb|center|Рисунок 2. Схема этапа распределения векторов по кластерам]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 3&amp;lt;/i&amp;gt; представлен информационный граф вычисления расстояния между двумя векторами &amp;lt;math&amp;gt;x_i = (x_{i1}, ..., x_{id}), i = 1, ..., n&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu^t_j = (\mu^t_{j1}, ..., \mu^t_{jd}) , j = 1, ..., k&amp;lt;/math&amp;gt;. Выполняется операция поэлементного вычитания двух векторов (вершины &amp;lt;i&amp;gt;-&amp;lt;/i&amp;gt;), затем возведение в квадрат (вершины &amp;lt;i&amp;gt;sqr&amp;lt;/i&amp;gt;), затем суммирование полученных результатов (вершина &amp;lt;i&amp;gt;+&amp;lt;/i&amp;gt;). На выходе получаем квадрат расстояния между векторами.&lt;br /&gt;
[[file:K-means-distance.PNG|800px|thumb|center|Рисунок 3. Схема вычисления расстояния между двумя векторами]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На &amp;lt;i&amp;gt;рисунке 4&amp;lt;/i&amp;gt; представлен информационный граф этапа пересчета центров масс кластеров &amp;lt;math&amp;gt;\mu^t_1, \mu^t_2,..., \mu^t_k&amp;lt;/math&amp;gt;. Для каждого кластера &amp;lt;math&amp;gt;S^t_j, j = 1, ..., k&amp;lt;/math&amp;gt; выполняется операция суммирования (вершина &amp;lt;math&amp;gt;sum_j&amp;lt;/math&amp;gt;) векторов, которые принадлежат данному кластеру. Кроме того, для каждого кластера выполняется операция определения его размера (вершина &amp;lt;math&amp;gt;size_j&amp;lt;/math&amp;gt;). Затем выполняется операция деления (вершина &amp;lt;i&amp;gt;/&amp;lt;/i&amp;gt;). На выходе получаем новые центры масс кластеров &amp;lt;math&amp;gt;\mu^{t+1}_1, \mu^{t+1}_2,..., \mu^{t+1}_k&amp;lt;/math&amp;gt;.&lt;br /&gt;
[[file:k-means-update.PNG|800px|thumb|center|Рисунок 4. Схема этапа пересчета центров масс кластеров]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро алгоритма имеет большие возможности для параллелизма:&lt;br /&gt;
* Распределение векторов по кластерам: вектора &amp;lt;math&amp;gt;x_i, x_j, i \neq j; i, j = 1, ..., n&amp;lt;/math&amp;gt; могут быть распределены по кластерам независимо друг от друга;&lt;br /&gt;
* Пересчет центров масс кластеров: центры масс кластеров &amp;lt;math&amp;gt;\mu_i, \mu_j, i \neq j; i, j = 1, ..., k&amp;lt;/math&amp;gt; могут быть пересчитаны независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
Однако, этап пересчета центров масс кластеров зависит от этапа распределения векторов по кластерам, так что эти этапы должны выполняться строго последовательно. Таким образом, параллельная сложность алгоритма может быть вычислена следующим образом: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} = i * (N_{distr} + N_{update})&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости алгоритма, &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; - параллельная сложность этапа распределения векторов по кластерам, &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; - параллельная сложность этапа пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{distr}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;распределения векторов по кластерам&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Для каждой пары векторов &amp;lt;math&amp;gt;(x_i, \mu_j), i = 1,...,n; j = 1, ..., k&amp;lt;/math&amp;gt; операция вычисления расстояния выполняется независимо.&lt;br /&gt;
* При выполнении операция вычисления расстояния операции вычитания и умножения выполняются независимо друг от друга, поэтому требуется только одно вычитание и одно умножение. Число операций сложения: &amp;lt;math&amp;gt;N^{+}_{distr} = O(log(d))&amp;lt;/math&amp;gt; согласно [[Нахождение_частных_сумм_элементов_массива_сдваиванием | алгоритму нахождения частичной суммы элементов массива путем сдваивания]]; &lt;br /&gt;
* Для нахождения минимума среди &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; элементов требуется &amp;lt;math&amp;gt;O(log(k))&amp;lt;/math&amp;gt; операций сравнения.&lt;br /&gt;
Таким образом, получаем, что &amp;lt;math&amp;gt;N_{distr} = O(log(k*d))&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассчитаем параллельную сложность &amp;lt;math&amp;gt;N_{update}&amp;lt;/math&amp;gt; этапа &amp;lt;i&amp;gt;пересчета центров масс кластеров&amp;lt;/i&amp;gt; в предположении наличия неограниченного числа процессоров для одной итерации. Нахождение центра масс &amp;lt;math&amp;gt;\mu_j, j = 1, ..., k&amp;lt;/math&amp;gt; кластера &amp;lt;math&amp;gt;S_j&amp;lt;/math&amp;gt; может выполняться независимо от нахождения центров масс других кластеров. Таким образом, получаем, что &amp;lt;math&amp;gt;N_{update} \leq O(log(n))&amp;lt;/math&amp;gt; в худшем случае, когда почти все векторы находятся в одном кластере. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Итоговая параллельная сложность алгоритма: &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;N_{k-means} \leq i * (log(k*d) + log(n)) \thicksim O(i * log(k*d*n)); i&amp;lt;/math&amp;gt; - количество итераций, необходимых для сходимости.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое положительное число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&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;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров;&lt;br /&gt;
# Чувствительность к выбросам и шумам, так как они учитываются при вычислении центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки. Алгоритм также является устойчивым к погрешностям, допускаемых при вычислениях, так как операция сложения на каждой новой итерации выполняется над входными данными. &lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: &amp;lt;math&amp;gt;{O(n*d*k*i) \over O(log(n*d*k)*i)} \thicksim O \bigg( {n*d*k \over log(n*d*k)} \bigg)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;math&amp;gt;{O(n*d*k*i) \over n*d+n+1} \thicksim {O(d*k*i) \over d+1} \thicksim O(k*i)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:GlotovES&amp;diff=10772</id>
		<title>Участник:GlotovES</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:GlotovES&amp;diff=10772"/>
		<updated>2016-10-15T17:17:52Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: Новая страница: «Глотов Евгений Сергеевич, группа 620»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Глотов Евгений Сергеевич, группа 620&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7394</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7394"/>
		<updated>2016-10-14T11:46:16Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO РАСПИСАТЬ&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
;Достоинства:&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;Недостатки:&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки&lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;math&amp;gt;{O(ndki) \over nd+n+1} = {O(dki) \over d+1} = O(ki)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7390</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7390"/>
		<updated>2016-10-14T11:44:24Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO РАСПИСАТЬ&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
;Достоинства:&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;Недостатки:&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки&lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;math&amp;gt;{ndki \over nd+n} = {dki \over d+1} = O(ki)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7383</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7383"/>
		<updated>2016-10-14T11:42:13Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO РАСПИСАТЬ&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
;Достоинства:&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;Недостатки:&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Устойчивость|&#039;&#039;Устойчивость&#039;&#039;]]: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки&lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Вычислительная мощность|&#039;&#039;Вычислительная мощность&#039;&#039;]]: &amp;lt;math&amp;gt;{ndki \over nd+n} = {dki \over d+1}&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&lt;br /&gt;
&lt;br /&gt;
;[[глоссарий#Детерминированность|&#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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7030</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7030"/>
		<updated>2016-10-13T22:14:29Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TODO РАСПИСАТЬ&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
;Достоинства:&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;Недостатки:&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
;Устойчивость: Алгоритм является устойчивым к погрешностям во входных данных, так как при вычислении центров кластеров расстояния между объектами усредняются, что приводит к уменьшению ошибки&lt;br /&gt;
&lt;br /&gt;
;Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
;Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
;Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
;Детерминированность: Алгоритм является недетерминированным, так как результат зависит от выбора исходных центров кластеров, а их оптимальный выбор неизвестен.&amp;lt;/p&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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7001</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=7001"/>
		<updated>2016-10-13T21:47:55Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Достоинства:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Недостатки:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++ &amp;lt;/b&amp;gt;&amp;lt;ref&amp;gt;[http://ilpubs.stanford.edu:8090/778/1/2006-13.pdf Arthur, D.; Vassilvitskii, S. (2007). &amp;quot;k-means++: the advantages of careful seeding&amp;quot;. Proceedings of the eighteenth annual ACM-SIAM symposium on Discrete algorithms. Society for Industrial and Applied Mathematics Philadelphia, PA, USA. pp. 1027–1035.]&amp;lt;/ref&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Устойчивость: todo&lt;br /&gt;
&lt;br /&gt;
Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Детерминированность:&lt;br /&gt;
Алгоритм является недетерминированным, так как результат зависит от выбора исходных центров кластеров, а их оптимальный выбор неизвестен.&amp;lt;/p&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;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6995</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6995"/>
		<updated>2016-10-13T21:33:55Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&amp;lt;/p&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;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Достоинства:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Недостатки:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++&amp;lt;/b&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Устойчивость: todo&lt;br /&gt;
&lt;br /&gt;
Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
Детерминированность: todo&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6993</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6993"/>
		<updated>2016-10-13T21:33:31Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&amp;lt;math&amp;gt;O(nkdi)&amp;lt;/math&amp;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;k&amp;lt;/math&amp;gt; - число кластеров, &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; - число итераций, требуемое для сходимости&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Достоинства:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Недостатки:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++&amp;lt;/b&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Устойчивость: todo&lt;br /&gt;
&lt;br /&gt;
Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
Детерминированность: todo&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6960</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6960"/>
		<updated>2016-10-13T21:05:19Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: Описание алгоритма: перенос ссылок в список литературы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом &amp;lt;ref&amp;gt;[http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf Steinhaus H. (1956). Sur la division des corps materiels en parties. Bull. Acad. Polon. Sci., C1. III vol IV: 801—804.]&amp;lt;/ref&amp;gt;, и почти одновременно его изобрел Стюарт Ллойд &amp;lt;ref&amp;gt;[http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf Lloyd S. (1957). Least square quantization in PCM’s. Bell Telephone Laboratories Paper.]&amp;lt;/ref&amp;gt;. Особую популярность алгоритм снискал после работы Джеймса Маккуина &amp;lt;ref&amp;gt;[https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf MacQueen J. (1967). Some methods for classification and analysis of multivariate observations. In Proc. 5th Berkeley Symp. on Math. Statistics and Probability, pages 281—297.]&amp;lt;/ref&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Основная идея алгоритма заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров.&amp;lt;/p&amp;gt; &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Достоинства:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Недостатки:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++&amp;lt;/b&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Устойчивость: todo&lt;br /&gt;
&lt;br /&gt;
Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
Детерминированность: todo&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6933</id>
		<title>Участник:IanaV/Алгоритм k means</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:IanaV/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_k_means&amp;diff=6933"/>
		<updated>2016-10-13T20:53:41Z</updated>

		<summary type="html">&lt;p&gt;GlotovES: Доработано общее описание алгоритма&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Авторы страницы: [[Участник:IanaV|Валуйская Я.А.]], [[Участник:GlotovES|Глотов Е.С.]]&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; (&amp;lt;i&amp;gt;k средних&amp;lt;/i&amp;gt;) - один из наиболее популярных алгоритмов кластеризации. Наиболее простой, но в то же время достаточно неточный метод кластеризации в классической реализации. Алгоритм был разработан в 1956 году математиком Гуго Штейнгаузом [http://www.laurent-duval.eu/Documents/Steinhaus_H_1956_j-bull-acad-polon-sci_division_cmp-k-means.pdf], и почти одновременно его изобрел Стюарт Ллойд [http://www-evasion.imag.fr/people/Franck.Hetroy/Teaching/ProjetsImage/2007/Bib/lloyd-1982.pdf]. Особую популярность алгоритм снискал после работы Джеймса Маккуина [https://pdfs.semanticscholar.org/a718/b85520bea702533ca9a5954c33576fd162b0.pdf]. &lt;br /&gt;
Алгоритм кластеризации &amp;lt;i&amp;gt;k-means&amp;lt;/i&amp;gt; решает задачу распределения &amp;lt;math&amp;gt;N&amp;lt;/math&amp;gt; наблюдений (элементов векторного пространства) на заранее известное число кластеров &amp;lt;math&amp;gt;K&amp;lt;/math&amp;gt;. Действие алгоритма таково, что он стремится минимизировать среднеквадратичное отклонение на точках каждого кластера. Основная идея заключается в том, что на каждой итерации перевычисляется центр масс для каждого кластера, полученного на предыдущем шаге, затем векторы разбиваются на кластеры вновь в соответствии с тем, какой из новых центров оказался ближе по выбранной метрике. Алгоритм завершается, когда на какой-то итерации не происходит изменения кластеров. &lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Исходные данные:&#039;&#039; &lt;br /&gt;
* множество наблюдений &amp;lt;math&amp;gt;X = \{x_1, x_2, ..., x_n\}&amp;lt;/math&amp;gt;, где каждое наблюдение &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* количество кластеров &amp;lt;math&amp;gt;k \in N, k \leq n&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Обозначения:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; - множество кластеров, которые удовлетворяют следующим условиям:&lt;br /&gt;
** &amp;lt;math&amp;gt;S_i \bigcap S_j = \emptyset, i \neq j&amp;lt;/math&amp;gt;; &lt;br /&gt;
** &amp;lt;math&amp;gt;X = {\bigcup \limits _{i = 1}^k S_i} &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mu_i \in R^d, i = 1, ..., k&amp;lt;/math&amp;gt; - центр масс кластера &amp;lt;math&amp;gt;S_i&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;d(u, v)&amp;lt;/math&amp;gt; - расстояние между векторами &amp;lt;math&amp;gt;u \in R^m, v \in R^m&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Выходные данные:&#039;&#039;&lt;br /&gt;
* &amp;lt;math&amp;gt;L = (l_1, l_2, ..., l_n)&amp;lt;/math&amp;gt; - набор меток, где метка &amp;lt;math&amp;gt;l_i \in N_{[1, k]}&amp;lt;/math&amp;gt; - является порядковым номером кластера, к которому принадлежит вектор &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;: &amp;lt;math&amp;gt; x_i \in S_{l_i}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;Цель алгоритма k-means&#039;&#039; - распределить наблюдения из входного множества &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; кластерам &amp;lt;math&amp;gt;S = \{S_1, S_2, ..., S_k \} &amp;lt;/math&amp;gt; таким образом, чтобы сумма квадратов расстояний от каждой точки кластера до его центра масс по всем кластерам была минимальной: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;math&amp;gt;\arg\min_{S} \sum_{i=1}^{k} \sum_{x \in S_i} (d(x, \mu_i))^2 &amp;lt;/math&amp;gt;,&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Алгоритм состоит из следующих шагов:&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;i&amp;gt;Инициализация центров масс&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге задаются начальные значения центров масс &amp;lt;math&amp;gt; \mu_1^1, ..., \mu_k^1&amp;lt;/math&amp;gt;. Существует несколько способов их выбора. Они будут рассмотрены ниже.&lt;br /&gt;
# &amp;lt;i&amp;gt;t-ый шаг итерации:&amp;lt;/i&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге каждый вектор &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; распределяется в свой кластер &amp;lt;math&amp;gt;S_i^t&amp;lt;/math&amp;gt; так, что: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x, \mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
#* &amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt;На данном шаге происходит пересчет центров масс кластеров, полученных на предыдущем этапе: &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
# &amp;lt;i&amp;gt;Критерий останова&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^t = \mu_i^{t+1},&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt;i = 1, ..., k&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительном ядром алгоритма является шаг 2, состоящий из следующих этапов:&lt;br /&gt;
# распределение векторов по кластерам;&lt;br /&gt;
# пересчет центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Распределение векторов по кластерам&amp;lt;/i&amp;gt; заключается в следующем: для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n&amp;lt;/math&amp;gt; необходимо посчитать расстояние между этим вектором и центром масс кластера &amp;lt;math&amp;gt;\mu_j^t, j = 1, ..., k&amp;lt;/math&amp;gt;. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;n * k&amp;lt;/math&amp;gt; операций вычисления расстояния между векторами. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Пересчет центров масс кластеров&amp;lt;/i&amp;gt; заключается в следующем: для каждого кластера &amp;lt;math&amp;gt;S_i^t \in S, i = 1, ..., k&amp;lt;/math&amp;gt; необходимо пересчитать кластер по формуле, приведенной в пункте выше. Следовательно, на каждой итерации необходимо выполнить &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; операций пересчета центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Расстояние между векторами&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; В данном алгоритме используется Евклидова метрика:  &amp;lt;br&amp;gt;&amp;lt;math&amp;gt;v \in R^m&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;u \in R^m: d(v, u) = \sqrt{\sum_{j=1}^{m} (v_j - u_j)^2} &amp;lt;/math&amp;gt;;&lt;br /&gt;
# Макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс кластера&amp;quot;&amp;lt;/i&amp;gt; &amp;lt;br&amp;gt; &amp;lt;math&amp;gt;\mu_i^{t+1} = \frac{1}{|S_i^t|} \sum_{x \in S_i^t} x&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Псевдокод алгоритма&amp;lt;/i&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;b&amp;gt;Входные данные&amp;lt;/b&amp;gt;  : Множество векторов &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;, количество кластеров &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt;&lt;br /&gt;
 &amp;lt;b&amp;gt;Выходные данные&amp;lt;/b&amp;gt; : Набор меток &amp;lt;math&amp;gt;L&amp;lt;/math&amp;gt; принадлежности к кластеру&lt;br /&gt;
 1  Инициализация центров масс &amp;lt;math&amp;gt;\mu_i^1, i = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 2  t := 1;&lt;br /&gt;
 3  Для каждого вектора &amp;lt;math&amp;gt;x_i \in X, i = 1, ..., n:&amp;lt;/math&amp;gt; &amp;lt;math&amp;gt;l_i^t = \arg \min_{j} (d(x_i,\mu_j^t))^2 , j = 1, ..., k&amp;lt;/math&amp;gt;;&lt;br /&gt;
 4  Для каждого кластера &amp;lt;math&amp;gt;S_i^t, i = 1, ..., k&amp;lt;/math&amp;gt; выполняется макрооперация &amp;lt;i&amp;gt;&amp;quot;Пересчет центра масс&amp;quot;&amp;lt;/i&amp;gt;;&lt;br /&gt;
 5  &amp;lt;b&amp;gt;if&amp;lt;/b&amp;gt; (&amp;lt;math&amp;gt;\exists i = 1, ..., k: \mu_i^t \neq \mu_i^{t+1}&amp;lt;/math&amp;gt;) {&lt;br /&gt;
 6      t := t + 1;&lt;br /&gt;
 7      &amp;lt;b&amp;gt;goto&amp;lt;/b&amp;gt; 3;&lt;br /&gt;
 8  } &amp;lt;b&amp;gt;else&amp;lt;/b&amp;gt; {&lt;br /&gt;
 9      &amp;lt;b&amp;gt;stop&amp;lt;/b&amp;gt;;&lt;br /&gt;
 10 };&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Входные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; векторов &amp;lt;math&amp;gt;x_i \in R^d, i = 1, ..., n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число кластеров &amp;lt;math&amp;gt;k \in N_{[1,n]}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем входных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n * d&amp;lt;/math&amp;gt; действительных чисел, 1 целое число&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Выходные данные&amp;lt;/i&amp;gt;:&lt;br /&gt;
* вектор меток &amp;lt;math&amp;gt;L \in N^n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Объем выходных данных&amp;lt;/i&amp;gt;:&lt;br /&gt;
&amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; целых чисел. &amp;lt;math&amp;gt;n \in [1,k]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Достоинства:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Алгоритм прозрачный и понятный, за счет чего очень прост в реализации;&lt;br /&gt;
# Алгоритм имеет высокую скорость работы в случае выбора оптимальных начальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Недостатки:&amp;lt;/i&amp;gt;&lt;br /&gt;
# Число кластеров является входным аргументом алгоритма. Таким образом, некорректный выбор данного параметра может привести к плохим результатам работы алгоритма, поэтому очень важно проводить диагностические прогоны для подбора оптимального количества кластеров;&lt;br /&gt;
# Алгоритм может сойтись к локальному минимуму (достижение глобального минимума не гарантируется);&lt;br /&gt;
# Результат сильно зависит от выбора начальных значений центров масс кластеров. Существует улучшенная версия алгоритма - &amp;lt;b&amp;gt;k-means++&amp;lt;/b&amp;gt;, которая предлагает свой способ нахождения начальных оптимальных значений центров масс кластеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Устойчивость: todo&lt;br /&gt;
&lt;br /&gt;
Сбалансированность: todo&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности: todo&lt;br /&gt;
&lt;br /&gt;
Вычислительная мощность: todo&lt;br /&gt;
&lt;br /&gt;
Детерминированность: todo&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Существуют следующие Open Source реализации алгоритма:&lt;br /&gt;
* [http://elki.dbs.ifi.lmu.de/ ELKI] - содержит реализацию алгоритма k-means на языке Java (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [http://www.cs.waikato.ac.nz/~ml/weka/ Weka] - содержит реализацию k-means на языке Java&lt;br /&gt;
* [http://mahout.apache.org/ Apache Mahout] - содержит реализацию k-means в парадигме MapReduce&lt;br /&gt;
* [https://spark.apache.org/ Spark Mllib] - содержит распределенную реализацию k-means&lt;br /&gt;
* [http://accord-framework.net/ Accord.NET] - содержит реализацию k-means на C# (в том числе реализацию улучшенного алгоритма k-means++)&lt;br /&gt;
* [https://github.com/mlpack/mlpack MLPACK] - содержит реализацию k-means на языке C++&lt;br /&gt;
* [http://opencv.org/ OpenCV] - содержит реализацию k-means на C++. А также есть обертки для языков Python и Java&lt;br /&gt;
* [https://www.scipy.org/ SciPy] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://scikit-learn.org/ Scikit-learn] - содержит реализацию k-means на языке Python&lt;br /&gt;
* [http://julialang.org/ Julia] - содержит реализацию алгоритма k-means на языке Julia&lt;br /&gt;
* [https://www.gnu.org/software/octave/ Octave] - содержит реализацию k-means на языке Octave&lt;br /&gt;
* [https://www.r-project.org/ R] - содержит реализацию k-means на языке R&lt;br /&gt;
* [http://torch.ch/ Torch] - содержит реализацию k-means на языке Lua&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;/div&gt;</summary>
		<author><name>GlotovES</name></author>
	</entry>
</feed>