Pular para o conteúdo

    Capítulo 11, Básico

    Reshape e transposição

    Os mesmos dados, em outra forma. Quase toda função de biblioteca espera uma forma específica, e remodelar é como você a entrega.

    Código deste capítulo: básico/cap11_reshape.py

    Remodelar sem mexer nos dados

    O reshape reorganiza os mesmos elementos em outra forma. O total precisa continuar o mesmo: ele nunca cria nem remove elementos. E o -1 em uma das dimensões significa "calcule você":

    básico/cap11_reshape.pylinhas 10 a 18
    import numpy as np
    
    arr = np.arange(12)
    print(arr.reshape(3, 4))
    print(arr.reshape(2, -1).shape, arr.reshape(-1, 3).shape)
    try:
        arr.reshape(5, 3)
    except ValueError as erro:
        print(erro)
    
    Saída
    [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]]
    (2, 6) (4, 3)
    cannot reshape array of size 12 into shape (5,3)
    

    Cinco vezes três dá 15, e o array tem 12 elementos, então o NumPy recusa. O reshape(2, -1) descobriu sozinho que a segunda dimensão é 6.

    Transpor, achatar e inserir eixos

    básico/cap11_reshape.pylinhas 23 a 27
    grade = np.arange(6).reshape(2, 3)
    print(grade.T.shape, grade.transpose().shape)
    print(grade.flatten(), grade.ravel())
    print(grade[:, np.newaxis, :].shape, grade[..., None].shape)
    print(np.squeeze(np.zeros((1, 3, 1))).shape)
    
    Saída
    (3, 2) (3, 2)
    [0 1 2 3 4 5] [0 1 2 3 4 5]
    (2, 1, 3) (2, 3, 1)
    (3,)
    
    FunçãoO que faz
    a.T ou a.transpose()Troca linhas e colunas. Em mais dimensões, inverte a ordem dos eixos
    a.swapaxes(i, j)Troca dois eixos específicos
    a.flatten()Achata para 1D e sempre copia
    a.ravel()Achata para 1D e devolve uma view quando possível
    np.newaxis ou NoneInsere um eixo de tamanho 1
    np.squeeze(a)Remove os eixos de tamanho 1

    A diferença entre flatten e ravel é a mesma do capítulo anterior: um copia, o outro compartilha memória, e alterar o resultado do ravel muda o original:

    básico/cap11_reshape.pylinhas 29 a 34
    r = grade.ravel()
    r[0] = 99
    print(grade[0, 0])
    f = grade.flatten()
    f[0] = -1
    print(grade[0, 0])
    
    Saída
    99
    99
    

    O truque do eixo extra

    Inserir um eixo de tamanho 1 é a forma de preparar um vetor para o broadcasting do próximo capítulo. Um vetor de forma (3,) vira uma coluna (3, 1) com reshape(-1, 1) ou com [:, None]:

    básico/cap11_reshape.pylinhas 39 a 40
    vetor = np.array([1, 2, 3])
    print(vetor.reshape(-1, 1))
    
    Saída
    [[1]
     [2]
     [3]]
    

    Um caso real: lote de imagens

    Um lote de 10 imagens de 28 por 28 pixels tem forma (10, 28, 28). Muitos modelos esperam cada imagem como um vetor de 784 números, ou seja, forma (10, 784). O -1 calcula o 784 sozinho:

    básico/cap11_reshape.pylinhas 45 a 46
    lote = np.zeros((10, 28, 28))
    print(lote.reshape(10, -1).shape)
    
    Saída
    (10, 784)
    

    reshape devolve view quando pode

    O reshape devolve uma view se a memória permitir e só copia quando não há outro jeito. Por isso, depois de um reshape, tenha em mente que alterar o resultado pode alterar o original. Em dúvida, confira com np.shares_memory.

    Exercício 1

    Coluna e planilha

    Escreva para_coluna(v) (um vetor 1D vira uma coluna) e lote_para_planilha(imagens) (de (n, h, w) para (n, h*w)).