L'algoritmo P2 è una bella scoperta. Funziona facendo diverse stime del quantile, aggiornandole periodicamente e usando l' interpolazione quadratica (non lineare, non cubica) per stimare il quantile. Gli autori sostengono che l'interpolazione quadratica funziona meglio nelle code rispetto all'interpolazione lineare e che i cubi diventerebbero troppo esigenti e difficili.
Non si afferma esattamente come questo approccio fallisca per i dati "dalla coda pesante", ma è facile da indovinare: le stime dei quantili estremi per le distribuzioni dalla coda pesante saranno instabili fino a quando non verrà raccolta una grande quantità di dati. Ma questo sarà un problema (in misura minore) anche se dovessi archiviare tutti i dati, quindi non aspettarti miracoli!
Ad ogni modo, perché non impostare marcatori ausiliari - chiamiamoli e x 6 - entro i quali sei altamente sicuro che il quantile mentirà e memorizzeremo tutti i dati compresi tra x 0 e x 6 ? Quando il buffer si riempie dovrai aggiornare questi marker, mantenendo sempre x 0 ≤ x 6 . Un semplice algoritmo per fare ciò può essere ideato da una combinazione di (a) la stima P2 corrente del conteggio quantile e (b) memorizzato del numero di dati inferiore a x 0 e il numero di dati maggiore di x 6x0x6x0x6x0≤x6x0x6. In questo modo è possibile, con elevata certezza, stimare il quantile così come se si avesse sempre l'intero set di dati sempre disponibile, ma è necessario solo un buffer relativamente piccolo.
In particolare, sto proponendo una struttura di dati per mantenere informazioni parziali su una sequenza di n valori di dati x 1 , x 2 , … , x n . Qui, y è un elenco collegato(k,y,n)nx1,x2,…,xny
y=(x(n)[k+1]≤x(n)[k+2]≤⋯≤x(n)[k+m]).
In questa notazione denota la i esimo più piccolo dei n x valori letto finora. m è una costante, la dimensione del buffer y .x(n)[i]ithn xmy
L'algoritmo inizia riempiendo con i primi m valori di dati rilevati e posizionandoli in ordine ordinato, dal più piccolo al più grande. Sia q essere il quantile da stimare; ad es. q = 0,99. Dopo aver letto x n + 1 ci sono tre possibili azioni:ymqqxn+1
Se , incrementa k .xn+1<x(n)[k+1]k
Se , non fare nulla.xn+1>x(n)[k+m]
Altrimenti, inserisci in y .xn+1y
In ogni caso, incremento .n
La procedura di inserimento inserisce in y in ordine ordinato e quindi elimina uno dei valori estremi in y :xn+1yy
Se , quindi rimuovere x ( n ) [ k + 1 ] da y e incrementare k ;k+m/2<nqx(n)[k+1]yk
Altrimenti, rimuovere da y .x(n)[k+m]y
Se è sufficientemente grande, questa procedura raggrupperà il vero quantile della distribuzione con alta probabilità. In qualsiasi fase n può essere stimato nel solito modo in termini di x ( n ) [ ⌊ q n ⌋ ] e x ( n ) [ ⌈ q n ⌉ ] , che probabilmente risiederà in y . (Credo che m debba solo ridimensionare come la radice quadrata della massima quantità di dati ( Nmnx(n)[⌊qn⌋]x(n)[⌈qn⌉]ymN), ma non ho effettuato un'analisi rigorosa per dimostrarlo. In ogni caso, l'algoritmo rileverà se è riuscito (confrontando e ( k + m ) / n con q ).k/n(k+m)/nq
Test con un massimo di 100.000 valori, usando m=2N−−√ and q=.5 (the most difficult case) indicates this algorithm has a 99.5% success rate in obtaining the correct value of x(n)[⌊qn⌋]. For a stream of N=1012 values, that would require a buffer of only two million (but three or four million would be a better choice). Using a sorted doubly linked list for the buffer requires O(log(N−−√)) = O(log(N)) effort while identifying and deleting the max or min are O(1) operations. The relatively expensive insertion typically needs to be done only O(N−−√) times. Thus the computational costs of this algorithm are O(N+N−−√log(N))=O(N) in time and O(N−−√) in storage.