6.11. Reduções¶
Uma redução colapsa um array ao longo de um ou mais eixos por meio de soma, média, mínimo e assim por diante. Cada redução é uma única chamada de biblioteca aplicada ao array inteiro, muito mais rápida do que o laço Python equivalente. O numpy cobre as mais corriqueiras:
sum()– total de todos os elementosmean()– média aritmética (soma dividida pela quantidade de elementos)std()– desvio padrão;ddof=ajusta o divisor (N - ddof)median()– valor central quando os elementos estão ordenados (percentil 50)all()/any()– reduções de valor-verdade sobre arrays booleanos
6.11.1. Sem a palavra-chave axis¶
Chamada sem axis=, uma redução retorna um escalar que cobre o array inteiro:
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. Com a palavra-chave axis¶
axis= contrai um eixo nomeado e mantém os demais intactos. O resultado é um array de uma dimensão (rank) a menos que a entrada:
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
A mesma regra de forma vale para toda redução: axis=0 colapsa o primeiro eixo, axis=1 colapsa o segundo, e assim por diante. Média / desvio padrão ao longo de uma linha, por exemplo, são escritos como np.mean(m, axis=1) e np.std(m, axis=1). O resultado tem o comprimento do outro eixo.
A palavra-chave keepdims=True mantém o eixo contraído no lugar com comprimento 1 em vez de removê-lo. A distinção importa quando o resultado reduzido precisa fazer broadcasting de volta contra o original: keepdims preserva a dimensão (rank), o que mantém as regras de broadcasting alinhadas eixo a eixo.
Subtrair de cada linha a média dessa linha é o uso canônico:
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
Sem keepdims, np.mean(m, axis=1) retorna um resultado 1-D de forma (3,). O broadcasting de (3, 4) - (3,) alinha (3,) como (1, 3) após o acréscimo de dimensão à esquerda, o que é incompatível com (3, 4): os últimos eixos discordam (4 contra 3) e nenhum deles é 1, então o numpy lança ValueError. keepdims=True é o que mantém a subtração válida.
6.11.3. O layout importa¶
Combinado com o layout row-major abordado em Formato e strides, reduzir ao longo do último eixo é o caso mais barato. A redução percorre o bloco de dados na direção em que ele está armazenado, sem saltos de uma linha para outra:
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 a aplicação pode escolher como dispor um buffer, coloque o eixo mais longo por último para que as reduções ao longo dele rodem na direção rápida.
6.11.4. Iteráveis como entrada¶
A maioria das reduções aceita um iterável Python (uma list, um range, uma tupla) no lugar de um ndarray. A conveniência custa alguns microssegundos pela conversão implícita – o que se acumula rápido em um laço. Quando os mesmos dados são reduzidos várias vezes, construa o ndarray uma vez e reaproveite-o.