Stima online dei quartili senza memorizzare osservazioni


13

Devo calcolare i quartili (Q1, mediana e Q3) in tempo reale su un ampio set di dati senza memorizzare le osservazioni. Per prima cosa ho provato l'algoritmo P square (Jain / Chlamtac) ma non ero soddisfatto (un po 'troppo utilizzo della CPU e non convinto almeno dalla precisione sul mio set di dati).

Ora uso l'algoritmo FAME ( Feldman / Shavitt ) per stimare la mediana al volo e provo a derivare l'algoritmo per calcolare anche Q1 e Q3:

M = Q1 = Q3 = first data value 
step =step_Q1 = step_Q3 = a small value
for each new data :
        # update median M 
        if M > data:
            M = M - step
        elif M < data:
            M = M + step
        if abs(data-M) < step:
            step = step /2

        # estimate Q1 using M
        if data < M:
            if Q1 > data:
                Q1 = Q1 - step_Q1
            elif Q1 < data:
                Q1 = Q1 + step_Q1
            if abs(data - Q1) < step_Q1:
                step_Q1 = step_Q1/2
        # estimate Q3 using M
        elif data > M:
            if Q3 > data:
                Q3 = Q3 - step_Q3
            elif Q3 < data:
                Q3 = Q3 + step_Q3
            if abs(data-Q3) < step_Q3:
                step_Q3 = step_Q3 /2

Per riprendere, utilizza semplicemente la mediana M ottenuta al volo per dividere il set di dati in due e quindi riutilizzare lo stesso algoritmo per Q1 e Q3.

Questo sembra funzionare in qualche modo ma non sono in grado di dimostrare (non sono un matematico). È agitato? Gradirei qualsiasi suggerimento o eventuale altra tecnica adatta al problema.

Grazie mille per il tuo aiuto !

==== EDIT =====

Per coloro che sono interessati a tali domande, dopo alcune settimane, ho finalmente finito semplicemente usando il Reservoir Sampling con un riverbero di 100 valori e questo mi ha dato risultati molto sontuosi (per me).


Stai cercando una prova che Q1 e Q2 convergono ai veri quantili quando il numero di esempi aumenta in modo simile all'analisi della catena markov nelle diapositive che hai collegato? In termini di implementazione, l'algoritmo sopra non sembra difettoso (ho testato quantili approssimativi per normale normale in R e l'algoritmo funziona bene).
Theja,

1
@Theja grazie, non sto cercando una prova (troppo lavoro) ma solo consigli e commenti, il problema principale che vedo è quello di basare il calcolo sulla stima corrente della mediana, come ha sottolineato whuber.
Louis Hugues,

Risposte:


3

La mediana è il punto in cui 1/2 delle osservazioni cadono sotto e 1/2 sopra. Allo stesso modo, il 25 ° perecentile è la mediana per i dati tra il minimo e la mediana e il 75 ° percentile è la mediana tra la mediana e la massima, quindi sì, penso che tu sia su un terreno solido applicando qualunque algoritmo mediano che usi per primo l'intero set di dati per partizionarlo e quindi sui due pezzi risultanti.

Aggiornamento :

Questa domanda su StackOverflow porta a questo articolo: Raj Jain, Imrich Chlamtac: l'algoritmo P² per il calcolo dinamico di quantiiles e istogrammi senza memorizzazione delle osservazioni. Commun. ACM 28 (10): 1076-1085 (1985) il cui abstract indica che probabilmente ti interessa molto:

Viene proposto un algoritmo euristico per il calcolo dinamico della mediana e di altri quantili. Le stime sono prodotte in modo dinamico man mano che vengono generate le osservazioni. Le osservazioni non sono memorizzate; pertanto, l'algoritmo ha un requisito di archiviazione molto piccolo e fisso indipendentemente dal numero di osservazioni. Ciò lo rende ideale per l'implementazione in un chip quantile che può essere utilizzato in controller e registratori industriali. L'algoritmo è ulteriormente esteso alla rappresentazione dell'istogramma. L'accuratezza dell'algoritmo viene analizzata.


4
Questa risposta trascura due punti sottili, uno non importante ma l'altro forse molto importante. L'importante è che la tecnica della doppia divisione calcoli le cerniere superiore e inferiore che possono differire leggermente dalla mediana, a seconda delle dimensioni del campione. L'importante è che la doppia divisione sembra essere basata su una stima corrente della mediana. Qualsiasi variazione tra questa stima e la mediana effettiva farà variare anche le cerniere. Intuitivamente, questo non dovrebbe essere un problema in quanto la quantità di dati aumenta, ma è un problema che necessita di analisi.
whuber

La stima diretta dei quartili non sarebbe soggetta a problemi simili? La stima diretta suddivide gli punti dati in un rapporto . Questo suddivide gli elementi in e quindi prende uno di quei "2" se lo divide in . Non sono un teorico, vero, ma, in generale, la differenza tra i due non sarebbe diversa al massimo da un punto a sinistra o a destra e converrebbe all'aumentare di ? Sì, potrebbe essere creata una distribuzione patologica, ma che soffrirebbe anche di una stima mediana diretta. Ovviamente, archiviare tutti i valori è ovviamente migliore. 1 : 3 2 : 2 1 : 1 nn1:32:21:1n
Avraham,

2
@Avraham, grazie per aver indicato il documento, come ho già detto, ho già provato l'algoritmo P-square di Chain e Chlamtac. nel mio set di dati l'algo che ho descritto dà un risultato migliore (MSE) ed è più veloce. Quindi mi chiedevo se potesse avere qualche problema. Come ha osservato Whuber, il fatto che utilizzi una stima corrente è un potenziale problema; ma non so se è davvero importante o no.
Louis Hugues,

Whoops, l'ho visto e l'ho dimenticato. Mie scuse.
Avraham,

0

Una leggera modifica al metodo che hai pubblicato e puoi calcolare qualsiasi percentile arbitrario, senza dover calcolare tutti i quantili. Ecco il codice Python:

class RunningPercentile:
    def __init__(self, percentile=0.5, step=0.1):
        self.step = step
        self.step_up = 1.0 - percentile
        self.step_down = percentile
        self.x = None

    def push(self, observation):
        if self.x is None:
            self.x = observation
            return

        if self.x > observation:
            self.x -= self.step * self.step_up
        elif self.x < observation:
            self.x += self.step * self.step_down
        if abs(observation - self.x) < self.step:
            self.step /= 2.0

e un esempio:

import numpy as np
import matplotlib.pyplot as plt

distribution = np.random.normal
running_percentile = RunningPercentile(0.841)
observations = []
for _ in range(1000000):
    observation = distribution()
    running_percentile.push(observation)
    observations.append(observation)

plt.figure(figsize=(10, 3))
plt.hist(observations, bins=100)
plt.axvline(running_percentile.x, c='k')
plt.show()

Distribuzione normale con 1 percentile STD

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.