Count sketch

Пусть у нас есть поток данных (stream) s1,s2,s3,,si,s_1, s_2, s_3, \dotsc, s_i, \dotsc, при этом все данные — элементы какого-то универсума U\UUU. Мы хотим уметь считать, сколько раз элемент xx встретился в этом потоке к моменту времени tt, то есть уметь считать значение функции

ft(x)=i=1tI(si=x)f_t(x) = \sum\limits_{i=1}^t \indic(s_i = x)

Будем решать задачу для фиксированной временной границы tt.

Задача подсчета

Дан поток данных S=s1,s2,s3,,sn1,snS = s_1, s_2, s_3, \dotsc, s_{n-1}, s_n. Можно считать, что мы сделали временной срез при t=nt = n.

Нам нужно оценивать количество вхождений элемента xx в этот поток SS — значение функции f(x)f(x).

f(x)=i=1nI(si=x)f(x) = \sum\limits_{i=1}^n \indic(s_i = x)

Но ответы на запросы лояльные. Мы даем ответ с точностью ε\varepsilon, при этом позволяем себе ошибаться с вероятностью δ\delta. Формально, P(f^(x)f(x)+εn)1δ\prob \big( \hat f (x) \le f(x) + \varepsilon n \big) \ge 1 - \delta, где f^(x)\hat f (x) — предсказанное нами количество вхождений.

А ещё нам нужно уметь обновлять поток — добавлять и удалять элементы.

Count-Min sketch

Для решения задачи подсчета можно использовать структуру данных Count-Min sketch. Она применима только тогда, когда в поток элементы только добавляются.

Будем использовать хеширование.

Пусть d=ln1/δd = \lceil \ln 1/\delta \rceil — глубина aka количество хеш-функций, и w=e/εw = \lceil e/\varepsilon \rceil — размер хеш-пространства. Счётчики будем хранить в двумерном массиве cN0d×wc \in \NN_0^{d \times w} высоты dd и ширины ww. Изначально массив cc проинициализирован нулями.

Создадим еще dd независимых хеш-функций h1,h2,,hd ⁣:U{1,2,,w}h_1, h_2, \dotsc, h_d \colon \UUU \surjto \{1, 2, \dotsb, w\}.

const real delta = 0.01 const real epsilon = 0.01 const int w = ceil(e / epsilon) const int d = ceil(ln(1 / delta)) const array h[d] array[int] c[d][w]

Обновление

При получении запроса на добавления в «счётчик» элемента xx мы для каждой строки ii массива cc увеличиваем значение соответствующего счётчика hi(x)h_i(x) на 11.

function add(self, element): for i = 0; i < d; i++: column = h[i](element) c[i][column] += 1

Оценка

Для получения оценки количества вхождений элемента xx в поток данных нам надо посчитать минимум по всем счётчикам, включающим в себя этот элемент:

f^(x)=min1   ⁣   ⁣idc[i][hi(i)]\hat f (x) = \min\limits_{1 \;\! \le \;\! i \le d} c[i][h_i(i)]

Все показатели счетчиков получаются завышенными, ведь у любой хеш-функции неизбежно будут коллизии. Когда мы берем минимум, мы выбираем наименее завышенную оценку.

Доказательство того, что структура работает, и работает хорошо.

Начнем с доказательства завышенности оценок. Для любой строки ii и любого элемента xx

c[i][hi(x)]=f(x)+yxhi(y)=hi(x)f(y)f(x)c[i][h_i(x)] = f(x) + \sum\limits_{\substack{y \;\! \neq \;\! x \\ h_i(y) = h_i(x)}} f(y) \ge f(x)

Хеш-функции hih_i «хорошие», то есть они свои входы равномерно распределяют по выходам.

Рассмотрим произвольную строку ii. Ошибка оценки Δi\Delta_i выражается как

Δi=c[i][hi(x)]f(x)=yxhi(y)=hi(x)f(y)\Delta_i = c[i][h_i(x)] - f(x) = \sum\limits_{\substack{y \;\! \neq \;\! x \\ h_i(y) = h_i(x)}} f(y)

Тогда математическое ожидание ошибки оценки

EΔi=y   ⁣   ⁣xf(y)P(hi(y)hi(x))=nf(x)w   ⁣   ⁣nw\expect \Delta_i = \sum\limits_{y \;\! \neq \;\! x} f(y) \cdot \prob \big( h_i(y) \neq h_i(x) \big) = \frac{n - f(x)}{w} \;\! \le \;\! \frac{n}{w}

Применим неравенство Маркова

P(Δia)EΔianwa\prob(\Delta_i \ge a) \le \frac{\expect \Delta_i}{a} \le \frac{n}{wa}

Выберем a=εna = \varepsilon n, тогда мы сможем получить оценку

P(Δiεn)1wε1e\prob(\Delta_i \ge \varepsilon n) \le \frac{1}{w \varepsilon} \le \frac{1}{e}

Но это только для одной строки. А при получении оценки мы выбираем минимум, значит, общая ошибка превысит εn\varepsilon n, только тогда, когда переоценку дадут все dd строк.

P(i=1d{Δi   ⁣   ⁣εn})   ⁣   ⁣(1e)d\prob \Bigg( \bigunion_{i=1}^d \{ \Delta_i \;\! \ge \;\! \varepsilon n \} \Bigg) \;\! \le \;\! \left( \frac{1}{e} \right)^d

Учитывая, что (1/e)deln1/δ=δ(1/e)^d \le e^{-\ln 1/\delta} = \delta, получаем оценку

P(f^(x)>f(x)+εn)δ\prob (\hat f (x) > f(x) + \varepsilon n ) \le \delta