Pular para o conteúdo

    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

    básico/cap14_agregacoes.pylinhas 10 a 15
    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))
    
    Saída
    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âmetroResumeResultado (para uma grade de 2 linhas e 3 colunas)
    axis=None (padrão)O array inteiroUm número
    axis=0Colapsa as linhas: um valor por colunaForma (3,)
    axis=1Colapsa as colunas: um valor por linhaForma (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:

    básico/cap14_agregacoes.pylinhas 20 a 21
    print(dados.std().round(3), dados.var().round(3), dados.std(ddof=1).round(3))
    print(np.percentile(dados, [25, 50, 75]))
    
    Saída
    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:

    básico/cap14_agregacoes.pylinhas 26 a 27
    salarios = np.array([3000, 3200, 3100, 2900, 50000])
    print(salarios.mean(), np.median(salarios))
    
    Saída
    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:

    básico/cap14_agregacoes.pylinhas 32 a 34
    votos = np.array([2, 1, 2, 3, 2, 1])
    valores, contagens = np.unique(votos, return_counts=True)
    print(valores, contagens)
    
    Saída
    [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:

    básico/cap14_agregacoes.pylinhas 39 a 40
    print(dados.sum(axis=1, keepdims=True))
    print(dados / dados.sum(axis=1, keepdims=True))
    
    Saída
    [[15]
     [32]]
    [[0.26666667 0.6        0.13333333]
     [0.34375    0.1875     0.46875   ]]
    

    Agregações em booleanos

    Como True vale 1 e False vale 0, sum conta, mean dá a proporção, any pergunta se algum é verdadeiro e all pergunta 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).