Algoritmi per calcolare la mediana corrente?


18

Su finestre di dimensioni inferiori, l' n log nordinamento potrebbe funzionare. Ci sono algoritmi migliori per raggiungere questo obiettivo?


1
Penso che questo sia il primo candidato ad essere spostato in Stack Overflow.

Forse, ma avrebbe bisogno di molte più spiegazioni su SO.
walkytalky,

2
La maggior parte dei programmatori conosce "mediana". (sort (array)) [lunghezza / 2] è un suggerimento abbastanza grande per coloro che hanno dimenticato. Anche nella sua forma più elementare per ogni nuovo punto devi solo fare una bisection / insert su metà dell'array ...
Paul


2
Troppo banale per essere più di un commento, ma il codice per la mediana di 3s è solo a + b + c - max (a, b, c) - min (a, b. C). Funziona bene anche se sono presenti dei legami. Questo era ovvio per me solo una volta che ci avevo pensato dal codice di qualcun altro (perché sta (in questo caso) aggiungendo e sottraendo per ottenere una mediana ???) e alcuni altri potrebbero avere la stessa reazione. max () e min () sono spesso implementati come funzioni superveloci. Purtroppo non esiste un simile trucco in generale.
Nick Cox,

Risposte:


11

È una cattiva forma ordinare un array per calcolare una mediana. Le mediane (e altri quantili) vengono in genere calcolate utilizzando l' algoritmo di selezione rapida , con complessità .O(n)

Puoi anche consultare la mia risposta a una recente domanda correlata qui .


7

Ecco un articolo che descrive un possibile algoritmo. Codice sorgente incluso e un'applicazione abbastanza seria (rilevamento dell'onda gravitazionale basata sull'interferometria laser), quindi puoi aspettarti che sia ben testato.


1
Il collegamento è interrotto e senza informazioni sul titolo o sull'autore è difficile trovare qualunque cosa a cui si riferisse.
Kristopher Johnson,


6

Se sei disposto a tollerare un'approssimazione, esistono altri metodi. Ad esempio, un'approssimazione è un valore il cui rango è entro una certa distanza (specificata dall'utente) dalla mediana reale. Ad esempio, la mediana ha un rango (normalizzato) 0,5 e se si specifica un termine di errore del 10%, si desidera una risposta con rango compreso tra 0,45 e 0,55.

Se tale risposta è appropriata, allora ci sono molte soluzioni che possono funzionare su finestre scorrevoli di dati. L'idea di base è quella di mantenere un campione dei dati di una certa dimensione (circa 1 / termine di errore) e calcolare la mediana su questo campione. Si può dimostrare che con alta probabilità, indipendentemente dalla natura dell'input, la mediana risultante soddisfa le proprietà che ho menzionato sopra.

Pertanto, la domanda principale è come mantenere un campione corrente dei dati di una certa dimensione, e ci sono molti approcci per questo, inclusa la tecnica nota come campionamento del serbatoio. Ad esempio, questo documento: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7136


4

Se si mantiene una finestra di lunghezza-k di dati come un elenco doppiamente collegato, quindi, mediante una ricerca binaria (per inserire ogni nuovo elemento man mano che viene spostato nella finestra) e una matrice circolare di puntatori (per individuare immediatamente gli elementi che deve essere eliminato), ogni spostamento della finestra richiede uno sforzo O (log (k)) per l'inserimento di un elemento, solo uno sforzo O (1) per eliminare l'elemento spostato fuori dalla finestra e solo uno sforzo O (1) per trovare la mediana (perché ogni volta che un elemento viene inserito o eliminato nell'elenco è possibile aggiornare un puntatore alla mediana nel tempo O (1)). Lo sforzo totale per elaborare una matrice di lunghezza N è quindi O ((nk) log (k)) <= O (n log (k)). Questo è meglio di qualsiasi altro metodo proposto finora e non è un'approssimazione, è esatto.


1
Potresti approfondire come proponi di fare una ricerca binaria in una lista doppiamente collegata?
NPE,

un "collegamento" consente di attraversare l'elenco in ordine ordinato; l'altro ti permette di attraversare nell'ordine in cui appaiono gli elementi. Tuttavia, non è chiaro come lo faresti con i puntatori, come domande @aix.
shabbychef,

2
@aix Penso che la tua intimazione sia corretta; Avrei bisogno di un elenco di salto indicizzabile, non solo di un elenco doppiamente collegato ordinato. L'idea è quella di avere una struttura di dati che consenta l'inserimento di un elemento, la cancellazione di un elemento e la ricerca della mediana nel tempo O (log (n)) atteso (o meglio).
whuber

3

Come hai detto, l'ordinamento sarebbe O(n·log n)per una finestra di lunghezza n. In questo modo si aggiunge un altro che l=vectorlengthrende il costo totale O(l·n·log n).

Il modo più semplice per farlo è mantenere un elenco ordinato degli ultimi n elementi in memoria quando si passa da una finestra a quella successiva. Poiché rimuovere / inserire un elemento da / in un elenco ordinato sono entrambi O(n)ciò comporterebbe costi di O(l·n).

pseudocodice:

l = length(input)
aidvector = sort(input(1:n))
output(i) = aid(n/2)
for i = n+1:l
    remove input(i-n) from aidvector
    sort aid(n) into aidvector
    output(i) = aid(n/2)


2

Se riesci a vivere con una stima anziché con la mediana reale, l' algoritmo Remedian (PDF) è 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) ...


0

Ho usato questa libreria C ++ di RunningStats in un'applicazione integrata. È la libreria di statistiche di corsa più semplice che abbia mai trovato.

Dal link:

Il codice è un'estensione del metodo di Knuth e Welford per calcolare la deviazione standard in un passaggio attraverso i dati. Calcola asimmetria e curtosi anche con un'interfaccia simile. Oltre a richiedere solo un passaggio tra i dati, l'algoritmo è numericamente stabile e preciso.


Quella pagina dice qualcosa sulla mediana?
musiphil,
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.