Qual è un buon algoritmo per stimare la mediana di un enorme set di dati read-once?


48

Sto cercando un buon algoritmo (che significa calcolo minimo, requisiti minimi di archiviazione) per stimare la mediana di un set di dati che è troppo grande per essere archiviato, in modo tale che ogni valore possa essere letto una sola volta (a meno che tu non lo memorizzi esplicitamente). Non ci sono limiti ai dati che si possono assumere.

Le approssimazioni vanno bene, purché sia ​​nota la precisione.

Qualche puntatore?


4
Forse, chiedere su Stackoverflow potrebbe ottenere risposte migliori.

2
@Srikant:> è un'area di ricerca piuttosto attiva nella statistica :) La soluzione più vicina ai limiti teorici inferiori in termini di archiviazione comporta anche alcuni costrutti di probabilità piuttosto intelligenti. Tutto sommato sono stato sorpreso quando l'ho guardato per la prima volta un paio di mesi fa; ci sono più statistiche qui di quanto sembri.
user603

Risposte:


6

Potresti raggruppare il set di dati in set di dati molto più piccoli (diciamo 100 o 1000 o 10.000 punti dati) Se poi calcolassi la mediana di ciascuno dei gruppi. Se lo facessi con abbastanza set di dati, potresti tracciare qualcosa come la media dei risultati di ciascuno dei set più piccoli e questo woul, eseguendo abbastanza set di dati più piccoli converge in una soluzione "media".


Questo è interessante e dove potrebbero entrare alcuni consigli statistici! Supponiamo che in totale abbia (diciamo) 500.000 punti iid e guardo gruppi di (diciamo) 1.000 di loro, e calcolo la mediana di ciascun gruppo. Ora ho 500 mediane. Esiste una teoria che potrebbe permettermi di calcolare un intervallo di confidenza per la mediana complessiva sulla base di queste 500 mediane?
PeterR,

4
Quindi, secondo un collega scomparso da tempo, il miglior apropoach sembra essere Chiranjeeb Buragohain e Subhash Suri. Quantili su flussi. cs.ucsb.edu/~suri/psdir/ency.pdf Mi piace anche l'approccio di Ian, poiché questi mediani di set di dati più piccoli convergeranno in una distribuzione normale, e così posso formare intervalli di confutazione per i mediani.
Peter,

10

Che ne dici di una procedura di binning? Supponiamo (a scopo illustrativo) di sapere che i valori sono compresi tra 1 e 1 milione. Imposta N bin, di dimensione S. Quindi se S = 10000, avresti 100 bin, corrispondenti ai valori [1: 10000, 10001: 20000, ..., 990001: 1000000]

Quindi, scorrere i valori. Invece di memorizzare ogni valore, basta incrementare il contatore nel cestino appropriato. Utilizzando il punto medio di ciascun cestino come stima, è possibile effettuare una ragionevole approssimazione della mediana. È possibile ridimensionare la risoluzione fino a ottenere la risoluzione desiderata, modificando la dimensione dei contenitori. Sei limitato solo da quanta memoria hai.

Dal momento che non sai quanto possono essere grandi i tuoi valori, basta scegliere una dimensione del cestino abbastanza grande da non rischiare di esaurire la memoria, usando alcuni rapidi calcoli sul retro della busta. Puoi anche conservare i bin in modo sparso, in modo tale da aggiungere un cestino solo se contiene un valore.

Modificare:

Il link ryfm fornisce un esempio di ciò, con l'ulteriore passaggio di utilizzare le percentuali cumulative per stimare più accuratamente il punto all'interno del cestino mediano, anziché semplicemente usare i punti medi. Questo è un bel miglioramento.


Il problema con l'approccio del binning è che non abbiamo un buon limite superiore per i dati, e quindi il punto medio per il cestino più grande dovrebbe essere enorme. Quindi, avremmo bisogno di un numero enorme di bin (non abbastanza memoria per quello), o di bin piuttosto ampi (il che porterebbe quindi a una risposta abbastanza imprecisa). E i dati non sono molto scarsi.
PeterR,

Dato che sei interessato solo alla mediana, perché non potresti allargare i bin a valori più alti della tua variabile?
Russellpierce,

drknexus - perché non sappiamo quale dovrebbe essere il cestino più grande.
PeterR

Hai qualche intuizione su quale sarà la gamma? Se sei abbastanza sicuro che oltre la metà delle risposte sarà inferiore al numero N, puoi rendere l'ultimo cestino grande quanto desideri. Forse il tuo ultimo cestino ha tutti i numeri maggiori di 1 trilione - sarebbe abbastanza alto? Con la quantità di memoria nei sistemi moderni è possibile archiviare MOLTI contenitori e ottenere una risoluzione abbastanza elevata. In termini di strutture di dati, non stiamo parlando di nulla di speciale e di memoria intensa qui.
chrisamiller,

Qualche intuizione? sì. E il tuo approccio potrebbe funzionare in generale. Tuttavia, in questo caso non possiamo avere molta memoria / calcolo. È in un'applicazione di rete in cui il dispositivo è in grado di vedere decine di migliaia di elementi al secondo e di cui MOLTA poca elaborazione rimane a questo scopo. Non lo scenario ideale / tipico, lo so, ma è questo che lo rende interessante!
PeterR,

9

Ti reindirizzo alla mia risposta a una domanda simile . In poche parole, è una lettura una volta, algoritmo "al volo" con complessità nel caso peggiore per calcolare la mediana (esatta).O(n)


8

L' algoritmo Rivest-Tarjan-Selection (a volte chiamato anche algoritmo mediana delle mediane) ti permetterà di calcolare l'elemento mediano in tempo lineare senza alcun ordinamento. Per set di dati di grandi dimensioni, questo può essere un po 'più veloce dell'ordinamento log-linear. Tuttavia, non risolverà il problema di archiviazione della memoria.



2

Non ho mai dovuto farlo, quindi questo è solo un suggerimento.

Vedo due (altre) possibilità.

Mezzi dati

  1. Carica a metà i dati e ordina
  2. Quindi leggi i valori rimanenti e confronta con l'elenco ordinato.
    1. Se il nuovo valore è più grande, scartalo.
    2. else inserisce il valore nell'elenco ordinato e rimuove il valore più grande da tale elenco.

Distribuzione campionaria

L'altra opzione è utilizzare un'approssimazione che coinvolge la distribuzione campionaria. Se i tuoi dati sono normali, l'errore standard per n moderato è:

1.253 * sd / sqrt (n)

Per determinare la dimensione di n di cui saresti felice, ho eseguito una rapida simulazione Monte-Carlo in R

n = 10000
outside.ci.uni = 0
outside.ci.nor = 0
N=1000
for(i in 1:N){
  #Theoretical median is 0
  uni = runif(n, -10, 10)
  nor  = rnorm(n, 0, 10)

  if(abs(median(uni)) > 1.96*1.253*sd(uni)/sqrt(n))
    outside.ci.uni = outside.ci.uni + 1

  if(abs(median(nor)) > 1.96*1.253*sd(nor)/sqrt(n))
    outside.ci.nor = outside.ci.nor + 1
}

outside.ci.uni/N
outside.ci.nor/N

Per n = 10000, il 15% delle stime mediane uniformi era al di fuori dell'IC.


3
Il set di dati è potenzialmente troppo grande per essere letto a metà ... è in un contesto di rete in cui il dispositivo che esegue l'elaborazione può vedere decine di migliaia di elementi al secondo e probabilmente ha memoria sufficiente per archiviarne solo poche centinaia. Inoltre i dati non sono sicuramente gaussiani. In realtà non si adatta bene a nessuna delle distribuzioni comuni.
PeterR,


1

Ecco una risposta alla domanda posta su StackOverflow: https://stackoverflow.com/questions/1058813/on-line-iterator-algorithms-for-estimating-statistical-median-mode-skewness/2144754#2144754

L'aggiornamento iterativo mediana + = eta * sgn (campione - mediana) sembra che potrebbe essere una strada da percorrere.


1
ma allora come scegliere eta, e cosa significa statisticamente? cioè come formare intervalli di confidenza per la mediana da questo risultato?
Peter,

@PeterR, ehi, qual è la soluzione finale che hai usato?
Aakash Goel,

1

L' algoritmo Remedian (PDF) fornisce una stima mediana a un passaggio con requisiti di archiviazione bassi e precisione ben definita.

Il rimedio con base b procede calcolando le mediane dei gruppi di osservazioni b, quindi le mediane di queste mediane, fino a quando rimane una sola stima. Questo metodo richiede semplicemente k matrici di dimensione b (dove n = b ^ k) ...


1

Se i valori che stai utilizzando rientrano in un determinato intervallo, ad esempio da 1 a 100000, puoi calcolare in modo efficiente la mediana su un numero estremamente elevato di valori (ad esempio, trilioni di voci), con un bucket intero (questo codice preso da EA con licenza BSD -utils / sam-stats.cpp)

class ibucket {
public:
    int tot;
    vector<int> dat;
    ibucket(int max) {dat.resize(max+1);tot=0;}
    int size() const {return tot;};

    int operator[] (int n) const {
        assert(n < size());
        int i;
        for (i=0;i<dat.size();++i) {
            if (n < dat[i]) {
                return i;
            }
            n-=dat[i];
        }
    }

    void push(int v) {
        assert(v<dat.size());
        ++dat[v];
        ++tot;
    }
};


template <class vtype>
double quantile(const vtype &vec, double p) {
        int l = vec.size();
        if (!l) return 0;
        double t = ((double)l-1)*p;
        int it = (int) t;
        int v=vec[it];
        if (t > (double)it) {
                return (v + (t-it) * (vec[it+1] - v));
        } else {
                return v;
        }
}

Inoltre, questo può essere esteso all'uso di un numero finito di bin per mediane in tempo reale, ecc.
Erik Aronesty,
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.