Estimativa on-line de quartis sem armazenar observações

13

Preciso calcular quartis (Q1, mediana e Q3) em tempo real em um grande conjunto de dados sem armazenar as observações. Tentei pela primeira vez o algoritmo do quadrado P (Jain / Chlamtac), mas não estava satisfeito com ele (um pouco de uso da CPU e não estava convencido pela precisão, pelo menos no meu conjunto de dados).

Eu uso agora o algoritmo FAME ( Feldman / Shavitt ) para estimar a mediana em tempo real e tento derivar o algoritmo para calcular também 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

Para retomar, ele simplesmente usa a mediana M obtida em tempo real para dividir o conjunto de dados em dois e, em seguida, reutilizar o mesmo algoritmo para Q1 e Q3.

Isso parece funcionar de alguma forma, mas não sou capaz de demonstrar (não sou matemático). É falho? Gostaria de receber qualquer sugestão ou eventual outra técnica adequada ao problema.

Muito obrigado pela sua ajuda!

==== EDIT =====

Para aqueles que estão interessados ​​em tais perguntas, depois de algumas semanas, finalmente acabei usando a Amostragem de Reservatório com um revervoir de 100 valores e deu resultados muito satististas (para mim).

Louis Hugues
fonte
Você está procurando uma prova de que Q1 e Q2 convergem para os quantis verdadeiros à medida que o número de exemplos aumenta de maneira semelhante à análise da cadeia de markov nos slides vinculados? Em termos de implementação, o algoritmo acima não parece falho (testei quantis aproximados para o normal normal em R e o algoritmo funciona bem).
Theja
1
@ Theja obrigado, não estou procurando uma prova (muito trabalho), mas apenas conselhos e comentários. O principal problema que vejo é basear o cálculo na estimativa de execução da mediana, como apontou o whuber.
Louis Hugues

Respostas:

3

A mediana é o ponto em que 1/2 das observações caem abaixo e 1/2 acima. Da mesma forma, o 25º perecentil é a mediana dos dados entre o mínimo e a mediana, e o 75º percentil é a mediana entre o mediano e o máximo, então sim, acho que você está em um terreno sólido, aplicando qualquer algoritmo de mediana usado primeiro o conjunto de dados inteiro para particioná-lo e, em seguida, nas duas partes resultantes.

Atualização :

Esta pergunta sobre o fluxo de pilha leva a este artigo: Raj Jain, Imrich Chlamtac: O algoritmo P² para cálculo dinâmico de quantiis e histogramas sem armazenar observações. Comum. ACM 28 (10): 1076-1085 (1985), cujo resumo indica que provavelmente é de grande interesse para você:

Um algoritmo heurístico é proposto para o cálculo dinâmico da mediana e de outros quantis. As estimativas são produzidas dinamicamente à medida que as observações são geradas. As observações não são armazenadas; portanto, o algoritmo tem um requisito de armazenamento fixo muito pequeno, independentemente do número de observações. Isso o torna ideal para implementar em um chip quantil que pode ser usado em controladores e gravadores industriais. O algoritmo é estendido ainda mais à plotagem do histograma. A precisão do algoritmo é analisada.

Avraham
fonte
4
Essa resposta ignora dois pontos sutis, um sem importância, mas o outro possivelmente muito importante. O que não é importante é que a técnica de dupla divisão calcula as dobradiças superior e inferior, que podem diferir ligeiramente da mediana, dependendo do tamanho da amostra. O importante é que a divisão dupla pareça basear-se em uma estimativa contínua da mediana. Qualquer variação entre essa estimativa e a mediana real fará com que as dobradiças também variem. Intuitivamente, isso não deve ser um problema, pois a quantidade de dados aumenta, mas é um problema que precisa de algumas análises.
whuber
A estimativa direta dos quartis não estaria sujeita a problemas semelhantes? A estimativa direta particionaria on pontos de dados em um 1:3Razão. Isso divide os elementos em2:2 e então pega um desses "2" se divide 1:1. Não sou teórico, é verdade, mas, em geral, a diferença entre os dois não seria diferente em, no máximo, um ponto à esquerda ou à direita e convergiria comonaumenta? Sim, uma distribuição patológica poderia ser criada, mas isso também sofreria com a estimativa mediana direta. Obviamente, armazenar todos os valores é melhor, é claro.
Avraham
2
@ Avraham, obrigado por apontar o artigo, como eu mencionei, eu já tentei o algoritmo do quadrado P da Chain e Chlamtac. no meu conjunto de dados, o algo que descrevi fornece um melhor resultado (MSE) e é mais rápido. Então, eu estava questionando se poderia ter algum problema, no entanto. Como observou Whuber, o fato de usar uma estimativa constante é um problema em potencial; mas não sei se é realmente importante ou não.
Louis Hugues
Opa, vi isso e esqueci. Me desculpe.
Avraham
0

Uma alteração muito pequena no método que você postou e você pode calcular qualquer percentil arbitrário, sem precisar calcular todos os quantis. Aqui está o código 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 um exemplo:

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()

Distribuição normal com 1 percentil de DST

parrowdice
fonte