Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 05.01.07 15:06
Оценка:
Здравствуйте,

Возникла недавно задача: есть последовательность 64-битных чисел s1, s2, ... sN, где N — достаточно большое (для определенности пусть будет 4 миллиарда)
требуется, обработав эту последовательность, определить, сколько различных элементов нахождится в этой последовательности (т.е., посчитать количество элементов без повторений). Сама послеодвательность находится во внешней памяти, Ответ можно дать приблизительно, с указанным интервалом ошибки.

Числа s1.. sN могут быть абсолютно любые 64-битные, т.е. нельзя просто добавлять числа в какую-то структуру данных типа хеша и потом почитать количество ключей — памяти не хватит (ее есть 2Гб).

кто-нибдуь может подсказать, в какую сторону копать?
Re: Кол-ва различных элементов в очень большом массиве
От: DronG Украина  
Дата: 05.01.07 16:04
Оценка:
Здравствуйте, ch00k, Вы писали:

C>Здравствуйте,


C>Возникла недавно задача: есть последовательность 64-битных чисел s1, s2, ... sN, где N — достаточно большое (для определенности пусть будет 4 миллиарда)

C>требуется, обработав эту последовательность, определить, сколько различных элементов нахождится в этой последовательности (т.е., посчитать количество элементов без повторений). Сама послеодвательность находится во внешней памяти, Ответ можно дать приблизительно, с указанным интервалом ошибки.

C>Числа s1.. sN могут быть абсолютно любые 64-битные, т.е. нельзя просто добавлять числа в какую-то структуру данных типа хеша и потом почитать количество ключей — памяти не хватит (ее есть 2Гб).


C>кто-нибдуь может подсказать, в какую сторону копать?


Можно попробывать следующее (точной оценки временной сложности и расхода памяти не делал):
Нужна длинная арифметика то есть работа с большими числами. Каждое новое число последовательности являеться порядковым номером простого числа, то есть мы производим преобразование числа из последовательности в простое число. Далее в нужно производить умножение каждого последующего простого числа на то произведение всех предыдущих, предварительно проверив не встретилось ли такое число на уже раньше. Проверка осуществляеться делением — если на цело то это число у нас уже есть и его добавлять, то есть умножать на уже накопленное произведение не будем. Не трудно организовать счетчик различных чисел так как есть процедура проверки. Загвоздка может быть в формировании простых чисел, хранении конечного произведения (так как чисел всего 2^32 может и хватить — все ж таки не 2^64 как в случае с другой структоруой данных)

Вобщем можно попробывать, рекомендую просмотреть теорию чисел, арифметку по модулю (может удасться теряя точность повысить плотность хранения) и другие похожие темы.
Re: Кол-ва различных элементов в очень большом массиве
От: Mab Россия http://shade.msu.ru/~mab
Дата: 05.01.07 16:12
Оценка:
Здравствуйте, ch00k, Вы писали:

C>кто-нибдуь может подсказать, в какую сторону копать?

В сторону внеших алгоритмов сортировки. Кнут, 3 том.
Re[2]: Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 05.01.07 21:44
Оценка:
Здравствуйте, Mab, Вы писали:

Mab>Здравствуйте, ch00k, Вы писали:


C>>кто-нибдуь может подсказать, в какую сторону копать?

Mab>В сторону внеших алгоритмов сортировки. Кнут, 3 том.

не получится обращаться к внешней памяти интенсивно — последовательность идет в иде потока, считывать можно ограниченное число раз и подряд
Re[2]: Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 05.01.07 21:49
Оценка:
Здравствуйте, DronG, Вы писали:

DG>Можно попробывать следующее (точной оценки временной сложности и расхода памяти не делал):

DG>Нужна длинная арифметика то есть работа с большими числами. Каждое новое число последовательности являеться порядковым номером простого числа, то есть мы производим преобразование числа из последовательности в простое число. Далее в нужно производить умножение каждого последующего простого числа на то произведение всех предыдущих, предварительно проверив не встретилось ли такое число на уже раньше. Проверка осуществляеться делением — если на цело то это число у нас уже есть и его добавлять, то есть умножать на уже накопленное произведение не будем. Не трудно организовать счетчик различных чисел так как есть процедура проверки. Загвоздка может быть в формировании простых чисел, хранении конечного произведения (так как чисел всего 2^32 может и хватить — все ж таки не 2^64 как в случае с другой структоруой данных)

DG>Вобщем можно попробывать, рекомендую просмотреть теорию чисел, арифметку по модулю (может удасться теряя точность повысить плотность хранения) и другие похожие темы.


Насчет ограничений по памяти — это будет произведение из 4 миллиардов простых чисел (в худшем случае). Занимать оно будет по самой грубой оценке (log P) * (4 миллиарда), бит где P — максимальное число. Памяти явно не хватит. Но идея интересная, попробую посмотреть.
Re: Кол-ва различных элементов в очень большом массиве
От: Андрей Тарасевич Беларусь  
Дата: 05.01.07 22:28
Оценка: +1
Здравствуйте, ch00k, Вы писали:

C>Числа s1.. sN могут быть абсолютно любые 64-битные, т.е. нельзя просто добавлять числа в какую-то структуру данных типа хеша и потом почитать количество ключей — памяти не хватит (ее есть 2Гб).


Хватит или не хватит памяти в этом случае зависит не от того, 64-битные числа или нет, а от того, наколько велико их разнообразие во входной последовательности. В общем случае, т.е. если входная последовательность совершенно никак не предсказуема, тут ничего не поделаешь: в памяти эту задачу решить в приниципе не возможно.
Best regards,
Андрей Тарасевич
Re[2]: Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 05.01.07 22:53
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Хватит или не хватит памяти в этом случае зависит не от того, 64-битные числа или нет, а от того, наколько велико их разнообразие во входной последовательности. В общем случае, т.е. если входная последовательность совершенно никак не предсказуема, тут ничего не поделаешь: в памяти эту задачу решить в приниципе не возможно.


точно распределение чисел неизвестно и оно вполне может быть равномерным. То, что точное решение при таких ограичениях получить нельзя, понятно. Может, есть какие-то вероятностные алгоритмы, в которых как-то можно привязать максимальную ошибку к фукнции распределения чисел и количеству используемой памяти?
Re[3]: Кол-ва различных элементов в очень большом массиве
От: WolfHound  
Дата: 06.01.07 11:56
Оценка:
Здравствуйте, ch00k, Вы писали:

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

А может опишешь задачу полностью? Возможно можно срезать углы в других местах.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Кол-ва различных элементов в очень большом массиве
От: Кодт Россия  
Дата: 06.01.07 13:36
Оценка: +1
Здравствуйте, ch00k, Вы писали:

C>Возникла недавно задача: есть последовательность 64-битных чисел s1, s2, ... sN, где N — достаточно большое (для определенности пусть будет 4 миллиарда)

C>требуется, обработав эту последовательность, определить, сколько различных элементов нахождится в этой последовательности (т.е., посчитать количество элементов без повторений). Сама послеодвательность находится во внешней памяти, Ответ можно дать приблизительно, с указанным интервалом ошибки.

Ну раз во внешней памяти, то почему бы не построить базу данных, способную вместить в себя такой объём? Удобнее всего, наверное, использовать Б-деревья.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: Кол-ва различных элементов в очень большом массиве
От: Mab Россия http://shade.msu.ru/~mab
Дата: 06.01.07 15:13
Оценка:
Здравствуйте, ch00k, Вы писали:

C>не получится обращаться к внешней памяти интенсивно — последовательность идет в иде потока, считывать можно ограниченное число раз и подряд

Алгоритмов, основанных на последовательном доступе, завались. Тот же самый merge sort. Или radix sort.
Re: Кол-ва различных элементов в очень большом массиве
От: KinK  
Дата: 07.01.07 12:16
Оценка: 4 (1)
Здравствуйте, ch00k, Вы писали:

C>кто-нибдуь может подсказать, в какую сторону копать?


Вариант:

Заводим массив, в котором будем хранить интервалы, в которых лежат входные данные: A[N], где A[j]={A[j].min, A[j].max}, N-выбираем исходя из количества памяти, которое не жалко. Чем больше N, тем больше будет интервалов и соответственно выше точность.

Для каждого числа X из входного потока выполняем следующие действия:
Если это число входит в один из уже существующих интервалов, то никаких действий не производим.
Иначе, если существует интервал, граничащий с этим числом, то расширяем его до этого числа. Если таких интервала два (число оказалось между ними), то объединяем эти интервалы, освобождая место под новый интервал.
Если число не граничит ни с одним интервалом и в массиве есть свободное место, то добавляем в него интервал {X,X}, если свободного места нет, то сначала ищем два наиболее близких друг к другу интервала (учитывая интервал {X,X}) и объединяем их.

В итоге получим набор интервалов, в которых лежат входные данные.

Если необходимы не сами интервалы, а только количество различных чисел, то при каждом объединении двух не смежных интервалов увеличиваем счётчик погрешности P на число равное расстоянию между этими интервалами.

Искомое количество различных чисел будет лежать между S и S-P, где S – сумма размеров всех полученных интервалов.

Комментарии:
1. Массив A[N] конечно же отсортированный
2. Вместо массива можно использовать дерево, это ускорит операции с интервалами, но увеличит требования к памяти
3. Вместо A[j].max можно хранить A[j].len

Пойдет?
Re[2]: Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 07.01.07 18:04
Оценка:
Здравствуйте, KinK, Вы писали:

KK>Пойдет?


Спасибо, очень интересно, попробую. Есть какие-нибудь публикации, где этот алгоритм (и подобные) бы описывался, давались бы оценки по зависимости памяти/размера массив/точности результата?
Re: Кол-ва различных элементов в очень большом массиве
От: Rft  
Дата: 09.01.07 22:09
Оценка:
Здравствуйте, ch00k, Вы писали:

C>Здравствуйте,


C>Возникла недавно задача: есть последовательность 64-битных чисел s1, s2, ... sN, где N — достаточно большое (для определенности пусть будет 4 миллиарда)

C>требуется, обработав эту последовательность, определить, сколько различных элементов нахождится в этой последовательности (т.е., посчитать количество элементов без повторений). Сама послеодвательность находится во внешней памяти, Ответ можно дать приблизительно, с указанным интервалом ошибки.

C>Числа s1.. sN могут быть абсолютно любые 64-битные, т.е. нельзя просто добавлять числа в какую-то структуру данных типа хеша и потом почитать количество ключей — памяти не хватит (ее есть 2Гб).


Путь у нас есть 4 миллиарда 64-битных чисел и 2 ГБ оперативной памяти, тогда можно подсчитать количество различных чисел, если считывать данные много раз.
В 2 ГБ памяти помещается около 250 миллионов 8 байтных чисел (64-битных).
1. Находим минимальное и максимальное число в последовательности.
2. Ищем число х между минимальным и максимальным, такое, что количество чисел, которые больше, либо равно минимального, но меньше x составляет не более 250 миллионов (Число x можно искать дихотомией).
3. Еще раз проходим массив и все числа, которые больше минимального, но меньше x заносим в массив в оперативной памяти.
4. Массив в оперативной памяти сортируем и подсчитываем количество различных чисел.
5. Теперь в качестве минимального числа принимаем число x и повторяем с пункта 2, до тех пор, пока число x не достигнет
максимального числа.

Нужно продумать еще вариант, когда количество каких-либо одинаковых чисел достаточно велико или даже превышает 250 миллионов.
Re: Кол-ва различных элементов в очень большом массиве
От: McSeem2 США http://www.antigrain.com
Дата: 09.01.07 23:38
Оценка:
Здравствуйте, ch00k, Вы писали:

C>кто-нибдуь может подсказать, в какую сторону копать?


Если распределение близко к равномерному и допустима некоторая ошибка, то можно взять небольшой кусок последовательности (который гарантированно влезет в память) и отсортировать его. Повторяем для других кусков и усредняем результат. Метод даст большую погрешность в случае существенно неравномерного распределения.

Если нужен точный результат, то без внешней памяти в файлах не обойтись. В этом случае сортируем куски, влезающие в память и пишем их в файлы. После чего, в один проход (синхронно по всем файлам) выполняем процедуру, напоминающую merge sort, но без записи результата, а подсчитываем количество неуникальных элементов.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: Кол-ва различных элементов в очень большом массиве
От: Кодт Россия  
Дата: 10.01.07 09:02
Оценка:
Здравствуйте, KinK, Вы писали:

KK>Заводим массив, в котором будем хранить интервалы, в которых лежат входные данные: A[N], где A[j]={A[j].min, A[j].max}, N-выбираем исходя из количества памяти, которое не жалко. Чем больше N, тем больше будет интервалов и соответственно выше точность.


KK>Для каждого числа X из входного потока выполняем следующие действия:

KK>Если это число входит в один из уже существующих интервалов, то никаких действий не производим.
KK>Иначе, если существует интервал, граничащий с этим числом, то расширяем его до этого числа. Если таких интервала два (число оказалось между ними), то объединяем эти интервалы, освобождая место под новый интервал.
KK>Если число не граничит ни с одним интервалом и в массиве есть свободное место, то добавляем в него интервал {X,X}, если свободного места нет, то сначала ищем два наиболее близких друг к другу интервала (учитывая интервал {X,X}) и объединяем их.

Для любого наперёд заданного N могу предложить входную последовательность с колоссальной потерей точности.
Скормим сперва числа вида 2k, где k = [1..N] — тем самым выберем всю доступную память.
Затем скормим число m — максимум последовательности. Очевидно, что оно вынужденно попадёт в последний интервал, превратив его в {2N,m}
Вот, собственно, и всё
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: Кол-ва различных элементов в очень большом массиве
От: raskin Россия  
Дата: 10.01.07 09:09
Оценка:
Кодт wrote:
> KK>Если число не граничит ни с одним интервалом и в массиве есть
> свободное место, то добавляем в него интервал {X,X}, если свободного
> места нет, то сначала ищем два наиболее близких друг к другу интервала
> (учитывая интервал {X,X}) и объединяем их.
>
> Для любого наперёд заданного N могу предложить входную
> последовательность с колоссальной потерей точности.
> Скормим сперва числа вида 2k, где k = [1..N] — тем самым выберем всю
> доступную память.
> Затем скормим число m — максимум последовательности. Очевидно, что оно
> вынужденно попадёт в последний интервал, превратив его в {2N,m}
> Вот, собственно, и всё

Я на эти грабли чуть не наступил. Он же сказал — ищем ближайшие. Найдём
2 и 4. Потеря точности в данном примере будет 1.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: Кол-ва различных элементов в очень большом массиве
От: Кодт Россия  
Дата: 10.01.07 14:03
Оценка:
Здравствуйте, raskin, Вы писали:

R>Я на эти грабли чуть не наступил. Он же сказал — ищем ближайшие. Найдём

R>2 и 4. Потеря точности в данном примере будет 1.

Не 1!
Множество интервалов [2;2], [4;4], ..., [2N-2;2N-2], [2N;m] сообщает нам, что встретились Umin..Umax уникальных чисел,
— Umin = 1+1+...+1+2 = N+1
— Umax = 1+1+...+1+m-2N = N-1+m-2N = m-N-1

Пример: N=3.
Последовательности
2 4 6 1000 и далее
— 1000 1000 1000 1000 1000 ... (993 раза)
— 7 8 9 ... 999
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: Кол-ва различных элементов в очень большом массиве
От: KinK  
Дата: 10.01.07 15:44
Оценка: 1 (1) +1
Здравствуйте, Кодт, Вы писали:

R>>Он же сказал — ищем ближайшие.

Я же сказал — ищем ближайшие.

К>Не 1!

К>Множество интервалов [2;2], [4;4], ..., [2N-2;2N-2], [2N;m] сообщает нам, что встретились Umin..Umax уникальных чисел,
К>- Umin = 1+1+...+1+2 = N+1
К>- Umax = 1+1+...+1+m-2N = N-1+m-2N = m-N-1

К>Пример: N=3.

К>Последовательности
К>2 4 6 1000 и далее
К>- 1000 1000 1000 1000 1000 ... (993 раза)
К>- 7 8 9 ... 999

Число m не объеденится с интервалом {2N-2;2N-2}. Объединятся интервалы {2;2} и {4;4} и добавится интервал {m;m}. Погрешность = 1.

Но в случае если диапазон входных данных имеет множество разрозненных диапазонов, погрешность действительно будет дико большой. Например, во входной последовательности находятся только чётные числа.

Зато алгоритм работает в один проход и при любой длине входной последовательности.

Если длина входной последовательности не сильно большая, есть возможность сделать несколько проходов и это не сильно накладно, то стоит присмотреться к алгоритму предложенному Rft.
Re: Кол-ва различных элементов в очень большом массиве
От: scolar  
Дата: 13.01.07 01:18
Оценка:
Здравствуйте, ch00k, Вы писали:

C>Здравствуйте,


C>Возникла недавно задача: есть последовательность 64-битных чисел s1, s2, ... sN, где N — достаточно большое (для определенности пусть будет 4 миллиарда)

C>требуется, обработав эту последовательность, определить, сколько различных элементов нахождится в этой последовательности (т.е., посчитать количество элементов без повторений). Сама послеодвательность находится во внешней памяти, Ответ можно дать приблизительно, с указанным интервалом ошибки.

C>Числа s1.. sN могут быть абсолютно любые 64-битные, т.е. нельзя просто добавлять числа в какую-то структуру данных типа хеша и потом почитать количество ключей — памяти не хватит (ее есть 2Гб).


C>кто-нибдуь может подсказать, в какую сторону копать?


Идея такова: ввести хэш-функцию во множество меньшего размера. Для значений хэш-функции пересчёт очевиден (отсортировать, пробежаться). Далее оценить вероятность коллизии и с учетом этого давать оценку числа уникальных значений для исходного множества.

Ещё одна эвристика: если есть возможность держать полученные хэши в виде множества (с быстрой проверкой принадлежности), то имеет смысл завести две (или несколько) хэш-функций разной природы — тогда если коллизии не по всем хэшам одновременно, то найден точно новый элемент (обратное, разумеется, неверно).
Re[2]: Кол-ва различных элементов в очень большом массиве
От: ch00k  
Дата: 13.01.07 14:53
Оценка:
Здравствуйте, scolar, Вы писали:

S>Здравствуйте, ch00k, Вы писали:


S>Идея такова: ввести хэш-функцию во множество меньшего размера. Для значений хэш-функции пересчёт очевиден (отсортировать, пробежаться). Далее оценить вероятность коллизии и с учетом этого давать оценку числа уникальных значений для исходного множества.


не работает, коллилии будут в любом случае, т.к. потенциальное количество различных значений крайне велико в вполне равно длине массива, а памяти всего 2 Гб

S>Ещё одна эвристика: если есть возможность держать полученные хэши в виде множества (с быстрой проверкой принадлежности), то имеет смысл завести две (или несколько) хэш-функций разной природы — тогда если коллизии не по всем хэшам одновременно, то найден точно новый элемент (обратное, разумеется, неверно).


Спасибо. Есть алгоритм Count-Sketch (http://www.cs.princeton.edu/courses/archive/spr04/cos598B/bib/CharikarCF.pdf), где эта идея развивается, но я пока не видел его обоснования для решения моей задачи.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.