Алгоритм P2 - хорошая находка. Он работает, делая несколько оценок квантиля, периодически обновляя их и используя квадратичную (не линейную, не кубическую) интерполяцию для оценки квантиля. Авторы утверждают, что квадратичная интерполяция работает лучше в хвостах, чем линейная интерполяция, а кубическая будет слишком суетливой и сложной.
Вы точно не заявляете, как этот подход не подходит для ваших данных с «тяжелыми хвостами», но легко догадаться: оценки экстремальных квантилей для распределений с «тяжелыми хвостами» будут нестабильными, пока не будет собран большой объем данных. Но это будет проблемой (в меньшей степени), даже если вы будете хранить все данные, так что не ждите чудес!
В любом случае, почему бы не установить вспомогательные маркеры - давайте назовем их и x 6 - в которых, как вы уверены, будет лежать квантиль, и хранить все данные, которые лежат между x 0 и x 6 ? Когда ваш буфер заполнится, вам нужно будет обновить эти маркеры, всегда сохраняя x 0 ≤ x 6 . Простой алгоритм для этого может быть разработан из комбинации (а) текущей оценки P2 квантиля и (б) сохраненных подсчетов количества данных, меньшего, чем х 0, и количества данных, превышающего х 6.x0x6x0x6x0≤x6x0x6, Таким образом, вы можете с высокой степенью достоверности оценить квантиль точно так же, как если бы у вас всегда был доступен весь набор данных, но вам нужен только относительно небольшой буфер.
В частности, я предлагаю структуру данных для хранения частичной информации о последовательности из n значений данных x 1 , x 2 , … , x n . Здесь у - это связанный список(k,y,n)nx1,x2,…,xny
y=(x(n)[k+1]≤x(n)[k+2]≤⋯≤x(n)[k+m]).
В этом обозначении обозначает i- е наименьшее из n x значений, прочитанных до сих пор. m - константа, размер буфера y .x(n)[i]ithn xmY
Алгоритм начинается с заполнения первыми m найденными значениями данных и размещения их в отсортированном порядке, от наименьшего к наибольшему. Пусть q - квантиль, которая будет оценена; например, q = 0,99. После прочтения x n + 1 возможны три действия:YмQQИксn + 1
Если , увеличить k .Иксn + 1< х( н )[ k + 1 ]К
Если , ничего не делать.Иксn + 1> х( н )[ к + м ]
В противном случае вставьте в y .Иксn + 1Y
В любом случае, увеличьте .N
Процедура вставки помещает в y в отсортированном порядке, а затем удаляет одно из крайних значений в y :Иксn + 1YY
Если , то удалить x ( n ) [ k + 1 ] из y и увеличить k ;k + m / 2 < n qИкс( н )[ k + 1 ]YК
В противном случае удалите из y .Икс( н )[ к + м ]Y
При условии, что достаточно велико, эта процедура с высокой вероятностью будет заключать в скобки истинный квантиль распределения. На любом этапе n его можно оценить обычным способом в терминах x ( n ) [ ⌊ q n ⌋ ] и x ( n ) [ ⌈ q n ⌉ ] , которые, вероятно, будут лежать в y . (Я полагаю, что m должен масштабироваться как квадратный корень из максимального количества данных ( NмNИкс( н )[ ⌊ qn ⌋]Икс( н )[ ⌈ qn ⌉]YмN), но я не провел строгий анализ, чтобы доказать это.) Во всяком случае, алгоритм определит, был ли он успешным (сравнивая и ( k + m ) / n с q ).к / н( к +m)/nQ
Тестирование до 100 000 значений с использованием иq=.5(самый сложный случай) указывают, что этот алгоритм имеет 99,5% успеха в получении правильного значения x ( n ) [ n q n ⌋ ] . Для потока сN=10 12 значений это потребовало бы буфера только из двух миллионов (но три или четыре миллиона были бы лучшим выбором). Использование отсортированного двусвязного списка для буфера требуетO(log( √м = 2N−−√Q= .5Икс( н )[ ⌊ qn ⌋]N= 1012=O(log(N))усилия при определении и удалении max или min являютсяO(1)операциями. Относительно дорогая вставка обычно должна быть сделана толькоO( √O ( журнал( N--√) )O(log(N))O(1)раз. Таким образом, вычислительные затраты этого алгоритма составляютO(N+ √O(N−−√)во времени иO( √O ( N+ N--√журнал( N) ) = O ( N)в хранилище.O ( N--√)