6.11. Riduzioni¶
Una riduzione contrae un array lungo uno o più assi sommando, calcolando la media, prendendo un minimo e così via. Ogni riduzione è una singola chiamata di libreria sull’intero array, molto più veloce del ciclo Python equivalente. numpy copre quelle di uso quotidiano:
sum()– totale di ogni elementomean()– media aritmetica (somma divisa per il numero di elementi)std()– deviazione standard,ddof=regola il divisore (N - ddof)median()– valore centrale quando gli elementi sono ordinati (50° percentile)argmin()/argmax()– l”indice dell’elemento minimo o massimoall()/any()– riduzioni di valore di verità su array booleani
6.11.1. Senza la parola chiave axis¶
Chiamata senza axis=, una riduzione restituisce uno scalare che copre l’intero array:
a = np.array([1, 2, 3, 4], dtype=np.float)
np.sum(a) # 10.0
np.mean(a) # 2.5
np.std(a) # 1.118...
np.median(a) # 2.5
b = np.array([40, 10, 30, 20], dtype=np.float)
np.max(b) # 40.0
np.argmax(b) # 0 (index of the maximum)
6.11.2. Con la parola chiave axis¶
axis= contrae un asse specifico e lascia gli altri intatti. Il risultato è un array con un rango inferiore di uno rispetto all’input:
m = np.arange(12, dtype=np.float).reshape((3, 4))
np.sum(m) # 66.0 - scalar
np.sum(m, axis=0) # length-4 - column sums
np.sum(m, axis=1) # length-3 - row sums
La stessa regola sulla forma si applica a ogni riduzione: axis=0 contrae il primo asse, axis=1 contrae il secondo e così via. La media / deviazione standard lungo una riga, per esempio, si scrivono np.mean(m, axis=1) e np.std(m, axis=1). Il risultato ha la lunghezza dell”altro asse.
La parola chiave keepdims=True mantiene al suo posto l’asse contratto con lunghezza 1 invece di eliminarlo. La distinzione è importante quando il risultato ridotto deve essere ripropagato (broadcasting) rispetto all’originale: keepdims preserva il rango, il che mantiene allineate asse per asse le regole del broadcasting.
Sottrarre da ogni riga la media di quella riga è l’uso canonico:
m = np.arange(12, dtype=np.float).reshape((3, 4))
row_means = np.mean(m, axis=1, keepdims=True)
# row_means has shape (3, 1)
centred = m - row_means
# (3, 4) - (3, 1) -> (3, 4), each row centred on its own mean
Senza keepdims, np.mean(m, axis=1) restituisce un risultato 1-D di forma (3,). Il broadcasting di (3, 4) - (3,) allinea (3,) come (1, 3) dopo l’aggiunta del rango, il che è incompatibile con (3, 4): gli ultimi assi non concordano (4 contro 3) e nessuno dei due è 1, quindi numpy solleva ValueError. keepdims=True è ciò che mantiene valida la sottrazione.
6.11.3. La disposizione conta¶
Combinata con la disposizione per righe (row-major) trattata in Forma e strides, ridurre lungo l”ultimo asse è il caso più economico. La riduzione percorre il blocco di dati nella direzione in cui è memorizzato, senza salti da una riga all’altra:
m = np.arange(2000, dtype=np.float).reshape((2, 1000))
np.sum(m, axis=1) # cheap - long axis is the inner one
np.sum(m, axis=0) # has to jump rows on every step
Quando l’applicazione può scegliere come disporre un buffer, metti l’asse lungo per ultimo affinché le riduzioni lungo di esso vengano eseguite nella direzione veloce.
6.11.4. Iterabili come input¶
La maggior parte delle riduzioni accetta un iterabile Python (una list, un range, una tupla) al posto di un ndarray. Questa comodità costa alcuni microsecondi per la conversione implicita – che si accumulano rapidamente in un ciclo. Quando gli stessi dati vengono ridotti più volte, costruisci l”ndarray una sola volta e passalo in giro.