<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Warmte</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Warmte"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%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/Warmte"/>
		<updated>2026-05-19T14:44:06Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82171</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82171"/>
				<updated>2022-01-24T19:05:15Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{m}}&amp;lt;/tex&amp;gt;. Также этот алгоритм способен оценивать значения, превышающие 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt;, используя 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за '''мощность''' набора количество различных элементов в нём.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора [[wikipedia:ru:Равномерное_распределение|равномерно распределенных]] на заданном интервале &amp;lt;tex&amp;gt;[0, m-1]&amp;lt;/tex&amp;gt; случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элементу исходного набора применяется [[wikipedia:ru:Хеш-функция|хеш-функция]] для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой [[wikipedia:ru:Дисперсия_случайной_величины|дисперсии]] получаемой величины, а также некоторых крайних случаев: к примеру, если хеш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;\log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хеш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k-1}&amp;lt;/tex&amp;gt; {{---}} выбранная хеш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m-1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = \log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хеша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хеш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хеш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок: &amp;lt;tex&amp;gt;E \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (\log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;&lt;br /&gt;
 \alpha_{r}\approx\begin{cases}&lt;br /&gt;
 r=4 &amp;amp; 0.673\\&lt;br /&gt;
 r=5 &amp;amp; 0.697\\&lt;br /&gt;
 r=6 &amp;amp; 0.709\\&lt;br /&gt;
 r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
 \end{cases}&lt;br /&gt;
 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Число &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; и будет итоговой оценкой мощности данного набора.&lt;br /&gt;
&lt;br /&gt;
==План доказательства==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Идеальным мультимножеством''' мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; называется последовательность, полученная произвольными повторениями и перестановками, применяемыми к &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; равномерно распределенным случайным величинам на действительном интервале [0, 1].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть алгоритм '''HyperLogLog''' применяется к идеальному мультимножеству мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; (число &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; нам неизвестно), используя &amp;lt;tex&amp;gt;reg = 2^r&amp;lt;/tex&amp;gt; корзин, и пусть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; {{---}} полученная результирующая оценка количества различных элементов в этом мультимножестве.&lt;br /&gt;
&lt;br /&gt;
# Оценка величины E в таком случае асимптотически почти несмещенная, а именно: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt; \frac{1}{n} \mathbb{E}(E) \overset{n \to \infty}{=} 1 + \delta_1(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_1(n)| &amp;lt; 5 \cdot 10^{-5}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
# Стандартная ошибка, равная &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)}&amp;lt;/tex&amp;gt;, вычисляется следующим образом: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)} \overset{n \to \infty}{=} \frac{\beta_{reg}}{\sqrt{reg}} + \delta_2(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_2(n)| &amp;lt; 5 \cdot 10^{-4}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\delta_1(n)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta_2(n)&amp;lt;/tex&amp;gt; представляют собой осциллирующие функции с маленькой амплитудой, поддающиеся вычислению. Хотя их влияние в теории может быть компенсировано только частично, ими можно безопасно пренебречь для всех практических целей.&lt;br /&gt;
Константа &amp;lt;tex&amp;gt;\beta_{reg}&amp;lt;/tex&amp;gt;, в свою очередь, вычисляется следующим образом: &lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\beta_{reg}=\begin{cases}&lt;br /&gt;
reg=16 &amp;amp; 1.106\\&lt;br /&gt;
reg=32 &amp;amp; 1.070\\&lt;br /&gt;
reg=64 &amp;amp; 1.054\\&lt;br /&gt;
reg=126 &amp;amp; 1.046\\&lt;br /&gt;
reg\to\infty &amp;amp; \sqrt{3 \log(2) - 1} = 1.03896&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основная задача представляет оценку асимптотической зависимости величин &amp;lt;tex&amp;gt;\mathbb{E}_n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n&amp;lt;/tex&amp;gt; от индикатора &amp;lt;tex&amp;gt;Z = \frac{1}{\sum 2^{-z_j}}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Краткий план доказательства имеет следующий вид: &lt;br /&gt;
&lt;br /&gt;
# Сначала выводятся значение величины &amp;lt;tex&amp;gt;\alpha_r&amp;lt;/tex&amp;gt;, которая и делает оценку &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; асимптотически почти несмещенной, и величина стандартной ошибки.&lt;br /&gt;
# Затем производится непосредственная оценка величин &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n(Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Поскольку значение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; достаточно сложно вычислить, сначала исследуется величина &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt;, то есть ситуация, когда ожидаемое значение величины &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; не фиксировано, а удовлетворяет закону Пуассона с некоторым параметром &amp;lt;tex&amp;gt;\lambda&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# После этого остаётся доказать, что при &amp;lt;tex&amp;gt;\lambda := n&amp;lt;/tex&amp;gt; поведение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt; асимптотически близко. &lt;br /&gt;
&lt;br /&gt;
С полным доказательством этой теоремы можно ознакомиться в [http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf оригинальной статье].&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;\mathcal{O}(2^r \cdot \log_2 \log_2 n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Практические оптимизации==&lt;br /&gt;
Полученное при помощи алгоритма '''HyperLogLog''' значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; может оказаться неточным и нуждается в корректировке:&lt;br /&gt;
* При &amp;lt;tex&amp;gt;E \leq \frac{5}{2}2^r&amp;lt;/tex&amp;gt; в оценке могут появляться нелинейные искажения, которые необходимо скорректировать. Вычислим количество &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; равных &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, обозначим эту величину за &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;V = 0&amp;lt;/tex&amp;gt;, то уже полученное алгоритмом значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается, иначе оно должно быть вычислено по формуле &amp;lt;tex&amp;gt;E_{result} = 2^r \log(\frac{2^r}{V})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В том случае, если значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; превосходит ограничение на размер &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, возрастает вероятность коллизии при хешировании и итоговая оценка также должна быть скорректирована. Рассмотрим 32-битный случай: при &amp;lt;tex&amp;gt;E &amp;gt; \frac{2^{32}}{30}&amp;lt;/tex&amp;gt; итоговое значение можно вычислить как &amp;lt;tex&amp;gt;E_{result} = -2^{32} \log(1 - \frac{E}{2^{32}})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В остальных случаях итоговая оценка &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается.&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82170</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82170"/>
				<updated>2022-01-24T18:59:05Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{m}}&amp;lt;/tex&amp;gt;. Также этот алгоритм способен оценивать значения, превышающие 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt;, используя 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за '''мощность''' набора количество различных элементов в нём.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора [[wikipedia:ru:Равномерное_распределение|равномерно распределенных]] на заданном интервале &amp;lt;tex&amp;gt;[0, m-1]&amp;lt;/tex&amp;gt; случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элементу исходного набора применяется [[wikipedia:ru:Хеш-функция|хеш-функция]] для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой [[wikipedia:ru:Дисперсия_случайной_величины|дисперсии]] получаемой величины, а также некоторых крайних случаев: к примеру, если хеш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;\log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хеш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k-1}&amp;lt;/tex&amp;gt; {{---}} выбранная хеш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m-1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = \log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хеша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хеш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хеш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок: &amp;lt;tex&amp;gt;E \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (\log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;&lt;br /&gt;
 \alpha_{r}\approx\begin{cases}&lt;br /&gt;
 r=4 &amp;amp; 0.673\\&lt;br /&gt;
 r=5 &amp;amp; 0.697\\&lt;br /&gt;
 r=6 &amp;amp; 0.709\\&lt;br /&gt;
 r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
 \end{cases}&lt;br /&gt;
 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Число &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; и будет итоговой оценкой мощности данного набора.&lt;br /&gt;
&lt;br /&gt;
==План доказательства==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Идеальным мультимножеством''' мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; называется последовательность, полученная произвольными повторениями и перестановками, применяемыми к &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; равномерно распределенным случайным величинам на действительном интервале [0, 1].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть алгоритм '''HyperLogLog''' применяется к идеальному мультимножеству мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; (число &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; нам неизвестно), используя &amp;lt;tex&amp;gt;reg = 2^r&amp;lt;/tex&amp;gt; корзин, и пусть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; {{---}} полученная результирующая оценка количества различных элементов в этом мультимножестве.&lt;br /&gt;
&lt;br /&gt;
# Оценка величины E в таком случае асимптотически почти несмещенная, а именно: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt; \frac{1}{n} \mathbb{E}(E) \overset{n \to \infty}{=} 1 + \delta_1(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_1(n)| &amp;lt; 5 \cdot 10^{-5}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
# Стандартная ошибка, равная &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)}&amp;lt;/tex&amp;gt;, вычисляется следующим образом: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)} \overset{n \to \infty}{=} \frac{\beta_{reg}}{\sqrt{r}} + \delta_2(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_2(n)| &amp;lt; 5 \cdot 10^{-4}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\delta_1(n)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta_2(n)&amp;lt;/tex&amp;gt; представляют собой осциллирующие функции с маленькой амплитудой, поддающиеся вычислению. Хотя их влияние в теории может быть компенсировано только частично, ими можно безопасно пренебречь для всех практических целей.&lt;br /&gt;
Константа &amp;lt;tex&amp;gt;\beta_{reg}&amp;lt;/tex&amp;gt;, в свою очередь, вычисляется следующим образом: &lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\beta_{reg}=\begin{cases}&lt;br /&gt;
reg=16 &amp;amp; 1.106\\&lt;br /&gt;
reg=32 &amp;amp; 1.070\\&lt;br /&gt;
reg=64 &amp;amp; 1.054\\&lt;br /&gt;
reg=126 &amp;amp; 1.046\\&lt;br /&gt;
reg\to\infty &amp;amp; \sqrt{3 \log(2) - 1} = 1.03896&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основная задача представляет оценку асимптотической зависимости величин &amp;lt;tex&amp;gt;\mathbb{E}_n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n&amp;lt;/tex&amp;gt; от индикатора &amp;lt;tex&amp;gt;Z = \frac{1}{2^{-z_j}}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Краткий план доказательства имеет следующий вид: &lt;br /&gt;
&lt;br /&gt;
# Сначала выводятся значение величины &amp;lt;tex&amp;gt;\alpha_r&amp;lt;/tex&amp;gt;, которая и делает оценку &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; асимптотически почти несмещенной, и величина стандартной ошибки.&lt;br /&gt;
# Затем производится непосредственная оценка величин &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n(Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Поскольку значение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; достаточно сложно вычислить, сначала исследуется величина &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt;, то есть ситуация, когда ожидаемое значение величины &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; не фиксировано, а удовлетворяет закону Пуассона с некоторым параметром &amp;lt;tex&amp;gt;\lambda&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# После этого остаётся доказать, что при &amp;lt;tex&amp;gt;\lambda := n&amp;lt;/tex&amp;gt; поведение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt; асимптотически близко. &lt;br /&gt;
&lt;br /&gt;
С полным доказательством этой теоремы можно ознакомиться в [http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf оригинальной статье].&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;\mathcal{O}(2^r \cdot \log_2 \log_2 n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Практические оптимизации==&lt;br /&gt;
Полученное при помощи алгоритма '''HyperLogLog''' значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; может оказаться неточным и нуждается в корректировке:&lt;br /&gt;
* При &amp;lt;tex&amp;gt;E \leq \frac{5}{2}2^r&amp;lt;/tex&amp;gt; в оценке могут появляться нелинейные искажения, которые необходимо скорректировать. Вычислим количество &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; равных &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, обозначим эту величину за &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;V = 0&amp;lt;/tex&amp;gt;, то уже полученное алгоритмом значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается, иначе оно должно быть вычислено по формуле &amp;lt;tex&amp;gt;E_{result} = 2^r \log(\frac{2^r}{V})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В том случае, если значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; превосходит ограничение на размер &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, возрастает вероятность коллизии при хешировании и итоговая оценка также должна быть скорректирована. Рассмотрим 32-битный случай: при &amp;lt;tex&amp;gt;E &amp;gt; \frac{2^{32}}{30}&amp;lt;/tex&amp;gt; итоговое значение можно вычислить как &amp;lt;tex&amp;gt;E_{result} = -2^{32} \log(1 - \frac{E}{2^{32}})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В остальных случаях итоговая оценка &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается.&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82160</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82160"/>
				<updated>2022-01-18T18:53:36Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{m}}&amp;lt;/tex&amp;gt;. Также этот алгоритм способен оценивать значения, превышающие 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt;, используя 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Обозначим за '''мощность''' набора количество различных элементов в нём.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора [[wikipedia:ru:Равномерное_распределение|равномерно распределенных]] случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элементу исходного набора применяется [[wikipedia:ru:Хеш-функция|хеш-функция]] для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой [[wikipedia:ru:Дисперсия_случайной_величины|дисперсии]] получаемой величины, а также некоторых крайних случаев: к примеру, если хэш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хэш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k-1}&amp;lt;/tex&amp;gt; {{---}} выбранная хэш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m-1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хэша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хэш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хэш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок: &amp;lt;tex&amp;gt;E \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;tex&amp;gt;&lt;br /&gt;
 \alpha_{r}\approx\begin{cases}&lt;br /&gt;
 r=4 &amp;amp; 0.673\\&lt;br /&gt;
 r=5 &amp;amp; 0.697\\&lt;br /&gt;
 r=6 &amp;amp; 0.709\\&lt;br /&gt;
 r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
 \end{cases}&lt;br /&gt;
 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Число &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; и будет итоговой оценкой мощности данного набора.&lt;br /&gt;
&lt;br /&gt;
==План доказательства==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Идеальным мультимножеством''' мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; называется последовательность, полученная произвольными повторениями и перестановками, применяемыми к &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; равномерно распределенным случайным величинам на действительном интервале [0, 1].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть алгоритм '''HyperLogLog''' применяется к идеальному мультимножеству мощностью &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; (число &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; нам неизвестно), используя &amp;lt;tex&amp;gt;reg = 2^r&amp;lt;/tex&amp;gt; корзин, и пусть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; {{---}} полученная результирующая оценка количества различных элементов в этом мультимножестве.&lt;br /&gt;
&lt;br /&gt;
# Оценка величины E в таком случае асимптотически почти несмещенная, а именно: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt; \frac{1}{n} \mathbb{E}(E) \overset{n \to \infty}{=} 1 + \delta_1(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_1(n)| &amp;lt; 5 \cdot 10^{-5}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
# Стандартная ошибка, равная &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)}&amp;lt;/tex&amp;gt;, вычисляется следующим образом: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)} \overset{n \to \infty}{=} \frac{\beta_{reg}}{\sqrt{r}} + \delta_2(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_2(n)| &amp;lt; 5 \cdot 10^{-4}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\delta_1(n)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta_2(n)&amp;lt;/tex&amp;gt; представляют собой осциллирующие функции с маленькой амплитудой, поддающиеся вычислению. Хотя их влияние в теории может быть компенсировано только частично, ими можно безопасно пренебречь для всех практических целей.&lt;br /&gt;
Константа &amp;lt;tex&amp;gt;\beta_{reg}&amp;lt;/tex&amp;gt;, в свою очередь, вычисляется следующим образом: &lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\beta_{reg}=\begin{cases}&lt;br /&gt;
reg=16 &amp;amp; 1.106\\&lt;br /&gt;
reg=32 &amp;amp; 1.070\\&lt;br /&gt;
reg=64 &amp;amp; 1.054\\&lt;br /&gt;
reg=126 &amp;amp; 1.046\\&lt;br /&gt;
reg\to\infty &amp;amp; \sqrt{3 log(2) - 1} = 1.03896&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основная задача представляет оценку асимптотической зависимости величин &amp;lt;tex&amp;gt;\mathbb{E}_n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n&amp;lt;/tex&amp;gt; от индикатора &amp;lt;tex&amp;gt;Z = \frac{1}{2^{-z_j}}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Краткий план доказательства имеет следующий вид: &lt;br /&gt;
&lt;br /&gt;
# Сначала выводятся значение величины &amp;lt;tex&amp;gt;\alpha_r&amp;lt;/tex&amp;gt;, которая и делает оценку &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; асимптотически почти несмещенной, и величина стандартной ошибки.&lt;br /&gt;
# Затем производится непосредственная оценка величин &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n(Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Поскольку значение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; достаточно сложно вычислить, сначала исследуется величина &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt;, то есть ситуация, когда ожидаемое значение величины &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; не фиксировано, а удовлетворяет закону Пуассона с некоторым параметром &amp;lt;tex&amp;gt;\lambda&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# После этого остаётся доказать, что при &amp;lt;tex&amp;gt;\lambda := n&amp;lt;/tex&amp;gt; поведение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt; асимптотически близко. &lt;br /&gt;
&lt;br /&gt;
С полным доказательством этой теоремы можно ознакомиться в [http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf оригинальной статье].&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;\mathcal{O}(2^r \cdot log_2 log_2 n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Практические оптимизации==&lt;br /&gt;
Полученное при помощи алгоритма '''HyperLogLog''' значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; может оказаться неточным и нуждается в корректировке:&lt;br /&gt;
* При &amp;lt;tex&amp;gt;E \leq \frac{5}{2}2^r&amp;lt;/tex&amp;gt; в оценке могут появляться нелинейные искажения, которые необходимо скорректировать. Вычислим количество &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; равных &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, обозначим эту величину за &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;V = 0&amp;lt;/tex&amp;gt;, то уже полученное алгоритмом значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается, иначе оно должно быть вычислено по формуле &amp;lt;tex&amp;gt;E_{result} = 2^r log(\frac{2^r}{V})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В том случае, если значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; превосходит ограничение на размер &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, возрастает вероятность коллизии при хешировании и итоговая оценка также должна быть скорректирована. Рассмотрим 32-битный случай: при &amp;lt;tex&amp;gt;E &amp;gt; \frac{2^{32}}{30}&amp;lt;/tex&amp;gt; итоговое значение можно вычислить как &amp;lt;tex&amp;gt;E_{result} = -2^{32} log(1 - \frac{E}{2^{32}})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В остальных случаях итоговая оценка &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается.&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82159</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82159"/>
				<updated>2022-01-18T18:19:14Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{2^r}}&amp;lt;/tex&amp;gt;. Также этот алгоритм способен оценивать значения, превышающие  10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt;, используя 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора равномерно распределенных случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элемента исходного набора применяется хеш-функция для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой дисперсии получаемой величины, а также некоторых крайних случаев: к примеру, если хэш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хэш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k - 1}&amp;lt;/tex&amp;gt; {{---}} выбранная хэш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хэша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хэш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хэш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;E \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\alpha_{r}\approx\begin{cases}&lt;br /&gt;
r=4 &amp;amp; 0.673\\&lt;br /&gt;
r=5 &amp;amp; 0.697\\&lt;br /&gt;
r=6 &amp;amp; 0.709\\&lt;br /&gt;
r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Доказательство==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Идеальным мультимножеством''' с количеством различных элементов &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; называется последовательность, полученная произвольными повторениями и перестановками, применяемыми к &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; равномерно распределенным случайным величинам на действительном интервале [0, 1].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть алгоритм '''HyperLogLog''' применяется к идеальному мультимножеству, содержащему &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; различных элементов (число &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; нам неизвестно), используя &amp;lt;tex&amp;gt;reg = 2^r&amp;lt;/tex&amp;gt; корзин, и пусть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; {{---}} полученная результирующая оценка количества различных элементов в этом мультимножестве.&lt;br /&gt;
&lt;br /&gt;
# Оценка величины E в таком случае асимптотически почти несмещенная, а именно: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt; \frac{1}{n} \mathbb{E}(E) \overset{n \to \infty}{=} 1 + \delta_1(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_1(n)| &amp;lt; 5 \cdot 10^{-5}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Стандартная ошибка, равная &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)}&amp;lt;/tex&amp;gt;, вычисляется следующим образом: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)} \overset{n \to \infty}{=} \frac{\beta_{reg}}{\sqrt{r}} + \delta_2(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_2(n)| &amp;lt; 5 \cdot 10^{-4}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\delta_1(n)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta_2(n)&amp;lt;/tex&amp;gt; представляют собой осциллирующие функции с маленькой амплитудой, поддающиеся вычислению. Хотя их влияние в теории может быть компенсировано только частично, ими можно безопасно пренебречь для всех практических целей.&lt;br /&gt;
Константа &amp;lt;tex&amp;gt;\beta_{reg}&amp;lt;/tex&amp;gt;, в свою очередь, вычисляется следующим образом: &lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\beta_{reg}=\begin{cases}&lt;br /&gt;
reg=16 &amp;amp; 1.106\\&lt;br /&gt;
reg=32 &amp;amp; 1.070\\&lt;br /&gt;
reg=64 &amp;amp; 1.054\\&lt;br /&gt;
reg=126 &amp;amp; 1.046\\&lt;br /&gt;
reg\to\infty &amp;amp; \sqrt{3 log(2) - 1} = 1.03896&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основная задача представляет оценку асимптотической зависимости величин &amp;lt;tex&amp;gt;\mathbb{E}_n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n&amp;lt;/tex&amp;gt; от индикатора &amp;lt;tex&amp;gt;Z = \frac{1}{2^{-z_j}}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Краткий план доказательства имеет следующий вид: &lt;br /&gt;
&lt;br /&gt;
# Сначала выводятся значение величины &amp;lt;tex&amp;gt;\alpha_r&amp;lt;/tex&amp;gt;, которая и делает оценку &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; асимптотически почти несмещенной, и величина стандартной ошибки.&lt;br /&gt;
# Затем производится непосредственная оценка величин &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n(Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Поскольку значение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; достаточно сложно вычислить, сначала исследуется величина &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt;, то есть ситуация, когда ожидаемое значение величины &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; не фиксировано, а удовлетворяет закону Пуассона с некоторым параметром &amp;lt;tex&amp;gt;\lambda&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# После этого остаётся доказать, что при &amp;lt;tex&amp;gt;\lambda := n&amp;lt;/tex&amp;gt; поведение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt; асимптотически близко. &lt;br /&gt;
&lt;br /&gt;
С полным доказательством этой теоремы можно ознакомиться в [http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf оригинальной статье].&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;2^r \cdot log_2(k) = 2^r \cdot log_2 log_2 m &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество возможных значений хэш-функции.&lt;br /&gt;
&lt;br /&gt;
==Практические оптимизации==&lt;br /&gt;
Полученное при помощи алгоритма HyperLogLog значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; может оказаться неточным и нуждается в корректировке:&lt;br /&gt;
* При &amp;lt;tex&amp;gt;E \leq \frac{5}{2}2^r&amp;lt;/tex&amp;gt; в оценке могут появляться нелинейные искажения, которые необходимо скорректировать. Вычислим количество &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; равных &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, обозначим эту величину за &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;V = 0&amp;lt;/tex&amp;gt;, то уже полученное алгоритмом значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается, иначе оно должно быть вычислено по формуле &amp;lt;tex&amp;gt;E_{result} = 2^r \frac{2^r}{V}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В том случае, если значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; превосходит ограничение на размер &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, итоговая оценка также должна быть скорректирована. Рассмотрим 32-битный случай: при &amp;lt;tex&amp;gt;E &amp;gt; \frac{2^{32}}{30}&amp;lt;/tex&amp;gt; итоговое значение можно вычислить как &amp;lt;tex&amp;gt;E_{result} = -2^{32} log(1 - \frac{E}{2^{32}})&amp;lt;/tex&amp;gt;. Это может быть полезным при больших &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, близких к (в нашем примере) 2^{32}, когда вероятность коллизии при хешировании становится довольно высокой.&lt;br /&gt;
* В остальных случаях итоговая оценка &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается.&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82158</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82158"/>
				<updated>2022-01-18T18:18:32Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{2^r}}&amp;lt;/tex&amp;gt;. Также этот алгоритм способен оценивать значения, превышающие  10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt;, используя 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора равномерно распределенных случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элемента исходного набора применяется хеш-функция для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой дисперсии получаемой величины, а также некоторых крайних случаев: к примеру, если хэш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хэш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k - 1}&amp;lt;/tex&amp;gt; {{---}} выбранная хэш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хэша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хэш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хэш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;E \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\alpha_{r}\approx\begin{cases}&lt;br /&gt;
r=4 &amp;amp; 0.673\\&lt;br /&gt;
r=5 &amp;amp; 0.697\\&lt;br /&gt;
r=6 &amp;amp; 0.709\\&lt;br /&gt;
r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Доказательство==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Идеальным мультимножеством''' с количеством различных элементов &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; называется последовательность, полученная произвольными повторениями и перестановками, применяемыми к &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; равномерно распределенным случайным величинам на действительном интервале [0, 1].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть алгоритм '''HyperLogLog''' применяется к идеальному мультимножеству, содержащему &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; различных элементов (число &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; нам неизвестно), используя &amp;lt;tex&amp;gt;reg = 2^r&amp;lt;/tex&amp;gt; корзин, и пусть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; {{---}} полученная результирующая оценка количества различных элементов в этом мультимножестве.&lt;br /&gt;
&lt;br /&gt;
# Оценка величины E в таком случае асимптотически почти несмещенная, а именно: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt; \frac{1}{n} \mathbb{E}(E) \overset{n \to \infty}{=} 1 + \delta_1(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_1(n)| &amp;lt; 5 \cdot 10^{-5}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Стандартная ошибка, равная &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)}&amp;lt;/tex&amp;gt;, вычисляется следующим образом: &amp;lt;br /&amp;gt; &amp;lt;tex&amp;gt;\frac{1}{n}\sqrt{\mathbb{D}_n(E)} \overset{n \to \infty}{=} \frac{\beta_{reg}}{\sqrt{r}} + \delta_2(n) + o(1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;|\delta_2(n)| &amp;lt; 5 \cdot 10^{-4}&amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt;reg \geq 16&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\delta_1(n)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta_2(n)&amp;lt;/tex&amp;gt; представляют собой осциллирующие функции с маленькой амплитудой, поддающиеся вычислению. Хотя их влияние в теории может быть компенсировано только частично, ими можно безопасно пренебречь для всех практических целей.&lt;br /&gt;
Константа &amp;lt;tex&amp;gt;\beta_{reg}&amp;lt;/tex&amp;gt;, в свою очередь, вычисляется следующим образом: &lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\beta_{reg}=\begin{cases}&lt;br /&gt;
reg=16 &amp;amp; 1.106\\&lt;br /&gt;
reg=32 &amp;amp; 1.070\\&lt;br /&gt;
reg=64 &amp;amp; 1.054\\&lt;br /&gt;
reg=126 &amp;amp; 1.046\\&lt;br /&gt;
reg\to\infty &amp;amp; \sqrt{3 log(2) - 1} = 1.03896&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основная задача представляет оценку асимптотической зависимости величин &amp;lt;tex&amp;gt;\mathbb{E}_n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n&amp;lt;/tex&amp;gt; от индикатора &amp;lt;tex&amp;gt;Z = \frac{1}{2^{-z_j}}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Краткий план доказательства имеет следующий вид: &lt;br /&gt;
&lt;br /&gt;
# Сначала выводятся значение величины &amp;lt;tex&amp;gt;\alpha_r&amp;lt;/tex&amp;gt;, которая и делает оценку &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; асимптотически почти несмещенной, и величина стандартной ошибки.&lt;br /&gt;
# Затем производится непосредственная оценка величин &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{D}_n(Z)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Поскольку значение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; достаточно сложно вычислить, сначала исследуется величина &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt;, то есть ситуация, когда ожидаемое значение величины &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; не фиксировано, а удовлетворяет закону Пуассона с некоторым параметром &amp;lt;tex&amp;gt;\lambda&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# После этого остаётся доказать, что при &amp;lt;tex&amp;gt;\lambda := n&amp;lt;/tex&amp;gt; поведение &amp;lt;tex&amp;gt;\mathbb{E}_n(Z)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathbb{E}_{\mathcal{P}(\lambda)}(Z)&amp;lt;/tex&amp;gt; асимптотически близко. &lt;br /&gt;
&lt;br /&gt;
С полным доказательством этой теоремы можно ознакомиться в [http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf оригинальной статье].&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;2^r \cdot log_2(k) = 2^r \cdot log_2 log_2 m &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество возможных значений хэш-функции.&lt;br /&gt;
&lt;br /&gt;
==Практические оптимизации==&lt;br /&gt;
Полученное при помощи алгоритма HyperLogLog значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; может оказаться неточным и нуждается в корректировке:&lt;br /&gt;
* При &amp;lt;tex&amp;gt;E \leq \frac{5}{2}2^r&amp;lt;/tex&amp;gt; в оценке могут появляться нелинейные искажения, которые необходимо скорректировать. Вычислим количество &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; равных &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, обозначим эту величину за &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;V = 0&amp;lt;/tex&amp;gt;, то уже полученное алгоритмом значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается, иначе оно должно быть вычислено по формуле &amp;lt;tex&amp;gt;E_{result} = 2^r \frac{2^r}{V}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В том случае, если значение &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; превосходит ограничение на размер &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, итоговая оценка также должна быть скорректирована. Рассмотрим 32-битный случай: при &amp;lt;tex&amp;gt;E &amp;gt; \frac{2^{32}}{30}&amp;lt;/tex&amp;gt; итоговое значение можно вычислить как &amp;lt;tex&amp;gt;E_{result} = -2^{32} log(1 - \frac{E}{2^{32}})&amp;lt;/tex&amp;gt;. Это может быть полезным при больших &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, близких к (в нашем примере) 2^{32}, когда вероятность коллизии при хешировании становится довольно высокой.&lt;br /&gt;
* В остальных случаях итоговая оценка &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; в корректировке не нуждается.&lt;br /&gt;
&lt;br /&gt;
==Литература==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Поиск количества различных элементов в потоке данных]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82148</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=82148"/>
				<updated>2022-01-15T11:59:23Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''HyperLogLog''' {{---}} это вероятностный алгоритм, оценивающий количество различных элементов в больших потоках данных. Является стриминговым алгоритмом (англ. [[wikipedia:en:Streaming_algorithm|streaming algorithm]]), то есть обрабатывает последовательно поступающие данные в один проход. &lt;br /&gt;
&lt;br /&gt;
Подобные алгоритмы используются в тех случаях, когда объемы обрабатываемых данных настолько велики, что получение точного ответа затребует пропорционально слишком большого объёма памяти, в то время как вероятностный алгоритм может дать близкий к точному ответ, будучи с точки зрения памяти намного более оптимальным.&lt;br /&gt;
&lt;br /&gt;
==Точность==&lt;br /&gt;
&lt;br /&gt;
При использовании &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; единиц дополнительной памяти алгоритм '''HyperLogLog''' оценивает количество различных элементов со стандартной ошибкой около &amp;lt;tex&amp;gt;\frac{1.04}{\sqrt{m}}&amp;lt;/tex&amp;gt;, то есть при оценке данных &amp;gt; 10&amp;lt;sup&amp;gt;9&amp;lt;/sup&amp;gt; этому алгоритму потребуется всего 1.5 kB памяти для получения ответа с точностью 2%. &lt;br /&gt;
&lt;br /&gt;
Предыдущий алгоритм '''LogLog''', использовавшийся для решения этой задачи, достигал сравнимой точности ответа при использовании 64% от оригинальных объемов памяти.&lt;br /&gt;
&lt;br /&gt;
==Идея алгоритма==&lt;br /&gt;
В основе алгоритма '''HyperLogLog''' лежит наблюдение, что мощность набора равномерно распределенных случайных чисел можно оценить, вычислив максимальное количество ведущих нулей в двоичном представлении каждого числа в наборе. Таким образом, если максимальное наблюдаемое количество начальных нулей равно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, то оценка количества различных элементов в наборе будет &amp;lt;tex&amp;gt;2^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суть алгоритма заключается в следующем: к каждому элемента исходного набора применяется хеш-функция для получения набора равномерно распределенных случайных чисел с той же мощностью, что и исходный набор. Затем мощность этого случайно распределенного набора оценивается с помощью описанного выше алгоритма.&lt;br /&gt;
&lt;br /&gt;
Но при таком подходе могут возникать различные проблемы за счёт большой дисперсии получаемой величины, а также некоторых крайних случаев: к примеру, если хэш некоторого элемента будет равен &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то максимальное количество ведущих нулей сразу станет равным &amp;lt;tex&amp;gt;log_2{m}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} максимальное значение выбранной хэш-функции. Чтобы избежать подобных проблем и минимизировать дисперсию, модифицируем алгоритм следующим образом: разделим исходный поток элементов на &amp;lt;tex&amp;gt;2^r&amp;lt;/tex&amp;gt; корзин, для каждой из них вычислим максимальное наблюдаемое количество начальных нулей среди элементов в этой корзине, а затем на основе полученных для всех корзин значений вычислим итоговый ответ на задачу. &lt;br /&gt;
&lt;br /&gt;
==Описание алгоритма==&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; {{---}} исходный набор элементов &amp;lt;tex&amp;gt;a_1 ... a_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;h : \mathcal{U} \to {0, 1 ... 2^k - 1}&amp;lt;/tex&amp;gt; {{---}} выбранная хэш-функция с возможными значениями от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;m - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;k = log_2{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} количество бит исходного хэша, характеризующих номер корзины, в которую будет отправлен соответствующий элемент.&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt; {{---}} максимальное наблюдаемое количество начальных нулей в корзине под номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём исходный набор &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; на наборы &amp;lt;tex&amp;gt;\mathcal{M}_0..\mathcal{M}_{2^r - 1}&amp;lt;/tex&amp;gt; следующим образом: для каждого поступающего элемента &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; вычислим его хэш &amp;lt;tex&amp;gt;h(a_i)&amp;lt;/tex&amp;gt; и представим его в двоичном виде. Тогда первые &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; бит этого двоичного представления будут характеризовать номер корзины &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, а оставшиеся биты сформируют остаточный хэш &amp;lt;tex&amp;gt;h'(a_i)&amp;lt;/tex&amp;gt;, который и будет использоваться для поиска максимального количества начальных нулей в корзине &amp;lt;tex&amp;gt;\mathcal{M}_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Hll_bins.jpg|512px]]&lt;br /&gt;
&lt;br /&gt;
Для каждой корзины вычислим соответствующее &amp;lt;tex&amp;gt;z_j&amp;lt;/tex&amp;gt;, равное максимальному количеству ведущих нулей среди элементов этой корзины. Тогда оценкой для числа различных элементов в корзине будет &amp;lt;tex&amp;gt;2^{z_j}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Логично было бы предположить, что в таком случае итоговым ответом на задачу будет &amp;lt;tex&amp;gt; \sum\limits_{j=0}^{2^{r - 1}} 2^{z_j} &amp;lt;/tex&amp;gt;, но такой подход приводит не к самому выгодному результату. Выгоднее всего будет пересчитывать результат при помощи среднего гармонического всех полученных оценок:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;result \approx \alpha \cdot (2^r)^2 \cdot I&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt; {{---}} это индикатор, вычисляемый по формуле &amp;lt;tex&amp;gt;I = (\sum\limits_{j=0}^{2^{r - 1}} \frac{1}{2^{z_j}})^{-1} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} корректирующий множитель, вычисляемый по формуле &amp;lt;tex&amp;gt;\alpha = (2^r  \int\limits_{0}^{\infty} (log_2{\frac{2 + u}{1 + u}})^{2^r} \,du )^{-1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поскольку множитель &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; может быть достаточно сложным для вычисления, можно подобрать его примерное значение в зависимости от &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tex&amp;gt;&lt;br /&gt;
\alpha_{r}\approx\begin{cases}&lt;br /&gt;
r=4 &amp;amp; 0.673\\&lt;br /&gt;
r=5 &amp;amp; 0.697\\&lt;br /&gt;
r=6 &amp;amp; 0.709\\&lt;br /&gt;
r\ge7 &amp;amp; \frac{0.7213}{1+\frac{1.079}{2^r}}&lt;br /&gt;
\end{cases}&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
Оценка времени работы: &amp;lt;tex&amp;gt;\mathcal{O}(n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в исходном наборе.&lt;br /&gt;
&lt;br /&gt;
Оценка дополнительной памяти: &amp;lt;tex&amp;gt;2^r \cdot log_2(k) = 2^r \cdot log_2 log_2 m &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество возможных значений хэш-функции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[[wikipedia:en:HyperLogLog | Wikipedia {{---}} HyperLogLog algorithm]]&lt;br /&gt;
*[http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf Philippe Flajolet, Éric Fusy, Olivier Gandouet and Frédéric Meunier {{---}} HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Продвинутые алгоритмы]]&lt;br /&gt;
[[Категория: Поиск количества различных элементов в потоке данных]]&lt;br /&gt;
[[Категория: Вероятностные алгоритмы]]&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Hll_bins.jpg&amp;diff=82147</id>
		<title>Файл:Hll bins.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Hll_bins.jpg&amp;diff=82147"/>
				<updated>2022-01-15T11:17:44Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=81807</id>
		<title>Участник:Warmte</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Warmte&amp;diff=81807"/>
				<updated>2021-12-22T09:21:56Z</updated>
		
		<summary type="html">&lt;p&gt;Warmte: Новая страница: «1.»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1.&lt;/div&gt;</summary>
		<author><name>Warmte</name></author>	</entry>

	</feed>