Capítulo 14, Básico
Agregações e o parâmetro axis
Um array cru raramente é a resposta. Você quer um número que o resuma: um total, uma média, uma dispersão. E, em arrays de duas dimensões, quase sempre quer esse número **por coluna** ou **por linha**.
Código deste capítulo: básico/cap14_agregacoes.py
As agregações mais usadas
import numpy as np
dados = np.array([[4, 9, 2], [11, 6, 15]])
print(dados.sum(), dados.mean(), np.median(dados))
print(dados.sum(axis=0), dados.sum(axis=1))
print(dados.max(axis=1), dados.argmax(), dados.argmax(axis=1))
47 7.833333333333333 7.5
[15 15 17] [15 32]
[ 9 15] 5 [1 2]
Sem axis, a agregação achata o array e resume tudo em um número só. Com axis, o NumPy resume ao longo daquele eixo, e a dimensão some do resultado.
O que o axis faz
| Parâmetro | Resume | Resultado (para uma grade de 2 linhas e 3 colunas) |
|---|---|---|
axis=None (padrão) | O array inteiro | Um número |
axis=0 | Colapsa as linhas: um valor por coluna | Forma (3,) |
axis=1 | Colapsa as colunas: um valor por linha | Forma (2,) |
Eu uso este modelo mental: axis=k é o eixo que desaparece do resultado. Em axis=0, o eixo das linhas desaparece e sobram as colunas.
O argmax e o argmin devolvem a posição do maior e do menor valor (sem axis, a posição no array achatado), em vez do valor.
Dispersão e posição
O desvio padrão e a variância têm uma sutileza: por padrão, o NumPy divide por N (a variância da população). Para tratar os dados como uma amostra, divide-se por N - 1, com ddof=1:
print(dados.std().round(3), dados.var().round(3), dados.std(ddof=1).round(3))
print(np.percentile(dados, [25, 50, 75]))
4.375 19.139 4.792
[ 4.5 7.5 10.5]
O np.percentile devolve os valores abaixo dos quais fica a porcentagem pedida: o de 50% é a mediana.
Mediana resiste a valores extremos, a média não
Um único valor extremo arrasta a média para longe do que é "típico", e a mediana mal se mexe. Por isso, em dados de salário, preço de imóveis e tempo de resposta, a mediana costuma ser a medida honesta:
salarios = np.array([3000, 3200, 3100, 2900, 50000])
print(salarios.mean(), np.median(salarios))
12440.0 3100.0
Contar valores distintos
O np.unique com return_counts=True devolve os valores diferentes e quantas vezes cada um aparece, sem laço:
votos = np.array([2, 1, 2, 3, 2, 1])
valores, contagens = np.unique(votos, return_counts=True)
print(valores, contagens)
[1 2 3] [2 3 1]
Agregar com `keepdims`
Mantendo a dimensão reduzida, o resultado ainda "encaixa" no array original por broadcasting. É o que o capítulo anterior usou para normalizar linhas:
print(dados.sum(axis=1, keepdims=True))
print(dados / dados.sum(axis=1, keepdims=True))
[[15]
[32]]
[[0.26666667 0.6 0.13333333]
[0.34375 0.1875 0.46875 ]]
Agregações em booleanos
Como
Truevale 1 eFalsevale 0,sumconta,meandá a proporção,anypergunta se algum é verdadeiro eallpergunta se todos são. Elas combinadas com as máscaras do capítulo 9 resolvem a maior parte das perguntas sobre dados.
Exercício 1
Um resumo por coluna
Escreva resumo_por_coluna(dados) que devolva um dicionário com o mínimo, o máximo e a média de cada coluna (cada valor é um array com um elemento por coluna).