2009-06-03 14 views
8

la versione di sviluppo di Django ha funzioni di aggregazione come AVG, il conte, Max, Min, StdDev, Somma, e varianza (link text). C'è una ragione che manca a Median nell'elenco?Funzione di aggregazione "mediana" mancante in Django?

Attuare uno sembra come sarebbe facile. Mi sto perdendo qualcosa? Quanto stanno facendo le funzioni aggregate dietro le quinte?

risposta

7

Bene, il motivo è probabilmente dovuto al fatto che è necessario tenere traccia di tutti i numeri per calcolare la mediana. Avg, Count, Max, Min, StDev, Sum e Variance possono essere calcolati con esigenze di archiviazione costanti. Cioè, una volta "registrato" un numero non ne avrai più bisogno.

FWIW, le variabili da tracciare sono: min, max, count, <n> = avg, <n^2> = media del quadrato dei valori.

2

una forte possibilità è che mediano non fa parte di SQL standard.

Inoltre, richiede una sorta, il che rende piuttosto costoso per il calcolo.

+0

ci sono lineari, non ordinamento, algoritmi: http://valis.cs.uiuc.edu/~sariel/research/CG/applets/linear_prog/median.html –

+0

algoritmo sbagliato, volevo dire bfprt : http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm_-_.22Median_of_Medians_algorithm.22 –

+0

@Todd Gardner: il primo collegamento è il "generale di selezione della partizione-based" ed è O (nlogn) non è lineare. Il sito è sbagliato. Sarebbe bello cancellare quel commento, ma lasciare il commento della mediana dei mediani. –

2

Non ho idea di quale back-end DB stai usando, ma se il tuo db supporta un altro aggregato, o puoi trovare un modo intelligente per farlo, puoi probabilmente accedervi facilmente tramite Aggregate.

1

FWIW, è possibile estendere PostgreSQL 8.4 e versioni successive per disporre di una funzione di aggregazione mediana con these code snippets.

Altri frammenti di codice (che lavorano per le vecchie versioni di PostgreSQL) sono shown here. Assicurati di leggere i commenti per questa risorsa.

15

Ecco la funzione mancante. Passare un set di query e il nome della colonna che si desidera trovare la mediana di:

def median_value(queryset, term): 
    count = queryset.count() 
    return queryset.values_list(term, flat=True).order_by(term)[int(round(count/2))] 

che non è stato così difficile come alcune delle altre risposte sembrano indicare. L'importante è lasciare che l'ordinamento db faccia tutto il lavoro, quindi se hai già la colonna indicizzata, questa è un'operazione super economica.

(aggiornamento 2016/01/28) Se si vuole essere più rigorosi sulla definizione di mediano per un numero pari di elementi, questo in media insieme il valore dei due valori medi.

def median_value(queryset, term): 
    count = queryset.count() 
    values = queryset.values_list(term, flat=True).order_by(term) 
    if count % 2 == 1: 
     return values[int(round(count/2))] 
    else: 
     return sum(values[count/2-1:count/2+1])/Decimal(2.0) 
+0

Esiste una piccola inesattezza in questa implementazione, quando il numero di elementi è pari. Citazione da https://en.wikipedia.org/wiki/Median: "Se c'è un numero pari di osservazioni, allora non esiste un singolo valore medio, la mediana viene in genere definita come la media dei due valori medi ". Penso che una volta recuperata la lista valori, è meglio usare una funzione "mediana" python (per tale funzione, vedere questa discussione: http://stackoverflow.com/questions/24101524/finding-median-of-list -in-python) –

+0

@o_c Questo è un punto valido, ma non penso che sia una buona idea usare la funzione mediana di python sull'intero set di dati - è un'operazione costosa in cui tutto quello che devo davvero fare è fare un piccolo cambiamento se il conto è pari. Vedrò se posso buttare qualcosa insieme. –

Problemi correlati