bigdata

In statistica e nel calcolo delle probabilità uno strumento molto usato è il quantile, utile per frazionare in parti uguali un insieme numerico di valori ordinati.

La domanda a cui voglio dare una risposta è: in cosa consiste l'utilità del quantile in statistica o nel calcolo delle probabilità? La risposta, prima ancora di capirne il significato, è la seguente: il quantile dà una rapida rappresentazione visiva della distribuzione.

Continuiamo con l'esempio iniziato nel paragrafo precedente dove analizzavamo l'insieme dei pesi dei bambini di tre classi primarie, un array contenente 90 valori compresi tra 15 e 35. Generando casualmente i valori campione dell'array pesiStudenti si otteneva in alcuni casi array con medesimi valori minimi e massimi ma con medie molto diverse. La tendenza centrale (media) permetteva di dare una rapida interpretazione del contenuto dell'insieme ma non forniva comunque una indicazione su come i valori dei pesi fossero distribuiti. Per questo viene in aiuto lo strumento quantile, o il più utilizzato quartile.

Il quartile è calcolabile su insiemi ordinati, di conseguenza per prima cosa dobbiamo ordinare l'array pesiStudenti, operazione semplice visto che il tipo array dispone già di questo metodo.

let pesiStudentiOrdinati = pesiStudenti.sorted()

 

L'array va quindi diviso in quattro gruppi, ognuno dei quali ha lo stesso numero di osservazioni, ovvero lo stesso numero di elementi. L'elemento di separazione di ogni gruppo è un quantile che assume il nome di quartile (visto che abbiamo diviso per 4). Avremo di conseguenza 3 punti di separazione denominati primo quartile (Q1), secondo quartile (Q2 o mediana) e terzo quartile (Q3).

Come primo passo calcoliamo la mediana (Q2), la stessa procedura potrà poi essere applicata alle due metà ottenendo i valori di Q1 e Q3. Il metodo di calcolo cambia se l'insieme ha un numero di elementi pari piuttosto che un numero di elementi dispari. Si veda la figura di seguito.

mediana

 

In figura è stato anche indicato il valore della media in quanto, come si può vedere, non è da confondersi con il valore mediano. Nel primo caso, in cui nell'array sono presenti 5 elementi, la mediana è l'elemento con indice 2, e vale 12. Nel secondo caso, array con 6 elementi, la mediana è il valore medio tra i valori con indici 2 e 3 e vale 13. Nel codice che segue si tiene conto di questi due casi.

let numElementi = pesiStudenti.count

var mediana = 0

 

if numElementi % 2 == 1 {

    mediana = pesiStudentiOrdinati[(numElementi-1)/2]

}

else {

    let primoElemento = pesiStudentiOrdinati[(numElementi/2)-1]

    let secondoElemento = pesiStudentiOrdinati[(numElementi/2)]

    mediana = (primoElemento+secondoElemento)/2

}


print
("Mediana: \(mediana)")

 

 

Con i valori inseriti nel precedente paragrafo questo è il risultato del calcolo:

Mediana: 26 

 

Prima di calcolare i valori del primo e del terzo quartile consideriamo che, come per il calcolo della media, tornerebbe utile disporre della proprietà "mediana" integrata nell'array. Per fare questo dobbiamo riprendere i concetti di extension, protocol, closure e riscrivere il codice come segue (listato completo):

extension Collection where Iterator.Element == Int, Index == Int {

    var media: Double {

        if isEmpty {

            return 0

        }

        return Double(reduce(0, +)) / Double(endIndex-startIndex)

    }

    

    var dispersione: Int {

        if isEmpty {

            return 0

        }

        return Int(self.max()! - self.min()!)

    }

    

    var mediana: Double {

        if isEmpty {

            return 0

        }

        if count % 2 == 1 {

            let idx = (count.hashValue-1)/2  // == *2/4

            return Double(self[idx])

        }

        let idx1 = count.hashValue/2-1

        let idx2 = count.hashValue/2

        return Double((self[idx1]+self[idx2])/2)

    }

    

    var primoQuartile: Double {

        if isEmpty {

            return 0

        }

        if count % 2 == 1 {

            let idx = (count.hashValue-1)/4  // == *1/4

            return Double(self[idx])

        }

        let idx1 = count.hashValue/4-1

        let idx2 = count.hashValue/4

        return Double((self[idx1]+self[idx2])/2)

    }

    

    var terzoQuartile: Double {

        if isEmpty {

            return 0

        }

        if count % 2 == 1 {

            let idx = (count.hashValue-1)*3/4

            return Double(self[idx])

        }

        let idx1 = count.hashValue*3/4-1

        let idx2 = count.hashValue*3/4

        return Double((self[idx1]+self[idx2])/2)

    }

}

 

var pesiStudenti = [32, 27, 21, 24, 31, 33, 26, 28, 18, 27, 20, 23, 29, 20, 15, 26, 27, 30, 20, 24, 33, 28, 31, 28, 29, 17, 33, 24, 17, 31, 31, 29, 18, 23, 18, 29, 16, 24, 24, 27, 28, 24, 33, 27, 26, 24, 30, 24, 28, 25, 17, 16, 30, 15, 20, 27, 19, 24, 24, 30, 32, 30, 18, 34, 28, 29, 28, 16, 34, 15, 30, 15, 27, 31, 25, 34, 19, 24, 24, 18, 22, 18, 20, 31, 15, 34, 34, 32, 18, 22]

 

let pesiStudentiOrdinati = pesiStudenti.sorted()

 

print("Dispersione: \(pesiStudenti.dispersione)")

print("Media: \(pesiStudenti.media)")

print("Mediana: \(pesiStudentiOrdinati.mediana)")

print("Primo Quartile: \(pesiStudentiOrdinati.primoQuartile)")

print("Terzo Quartile: \(pesiStudentiOrdinati.terzoQuartile)")

 

Si ottiene la seguente stampa:

Dispersione: 19
Media: 25.1
Mediana: 26.0
Primo Quartile: 20.0
Terzo Quartile: 30.0

 

La cosa interessante è che tramite l'uso del meccanismo della extension applicato al protocol collection a cui gli array sono conformi si ottengono delle proprietà che permettono di semplificare l'uso delle funzioni dispersione, media, mediana ecc.. ottenendo  la stessa immediatezza che si ha in linguaggi specializzati in statistica come 'R'.

Ottenere questa semplificazione richiede però una conoscenza del linguaggio swift che superi l'approccio iniziale. Riassumiamo i concetti espressi:

  1. Abbiamo visto che la dispersione è calcolabile sottraendo al valore massimo dell'insieme il valore minimo. Il range di valori che si ottiene indica quanto si "disperdono" i valori nell'insieme; infatti se invece del valore 19, che abbiamo ricavato, avessimo avuto un valore prossimo allo zero, il risultato sarebbe stato quello di un insieme con valori pressoché uguali.
  2. La media, chiamata anche tendenza centrale, è il valore più utilizzato nella statistica comunemente conosciuta in quanto fornisce una indicazione sull'insieme nella sua totalità.
  3. La mediana o secondo quartile, fornisce un valore che non va confuso con la media, nonostante la somiglianza del nome, in quanto è il valore che divide perfettamente a metà l'insieme, ovvero è il valore che, una volta ordinato l'insieme, ha alla sua sinistra lo stesso identico numero di elementi che ha alla sua destra.
  4. Il primo quartile è l'elemento che ha alla sua sinistra 1/4 degli elementi dell'insieme e alla sua destra i 3/4.
  5. Il terzo quartile è l'elemento che ha alla sua sinistra 3/4 degli elementi dell'insieme e alla sua destra i 1/4.
  6. Abbiamo visto come calcolare il secondo quartile tramite una funzione dedicata che teneva in considerazione le due possibilità: insieme con un numero di elementi pari e insieme con un numero di elementi dispari.
  7. Abbiamo successivamente inserito la funzione all'interno di una estensione del protocollo collection in modo da avere una computed property di nome "mediana". La stessa cosa abbiamo fatto per il primo e terzo quartile e per la dispersione.

Prendiamo in esame la computed property terzo quartile per vedere com'è stata sviluppata.

Per prima cosa si decide il tipo che la proprietà deve restituire, in questo caso Double perchè il calcolo che si effettua potrebbe non restituire un valore intero. Con il primo if si verifica che l'array non sia vuoto, nel caso ritorna un valore zero. isEmpty è una proprietà della collection alla quale si accede ovviamente senza alcun prefisso.

Successivamente si verifica se il numero di elementi dell'array è dispari, per fare questo si interroga la proprietà count. In caso affermativo si calcola l'indice dell'array in cui si trova l'elemento terzo quartile. Il metodo di calcolo considera che il terzo quartile si trova una posizione prima del primo elemento dei 3/4 rimanenti dell'insieme. Viene utilizzata la proprietà hashValue di count in quanto l'indice dell'array deve essere conforme al protocollo hashable. L'istruzione successiva ritorna il valore dell'array corrispondente all'indice calcolato preoccupandosi di renderlo compatibile con il tipo che la computed property deve restituire (Double).

All'istruzione successiva arrivo solo se l'insieme non è vuoto e se ha un numero pari di elementi. Le istruzioni che seguono sono analoghe a quelle già viste. Il metodo di calcolo con due indici è quello indicato nell'immagine sopra riportata che fa riferimento ad un array campione di 6 elementi.

Vedremo nei prossimi appunti quanto siano utili i quartili per avere un'impressione visiva della distribuzione.