Skip to content

    Chapter 11, Basic

    Reshape and transpose

    The same data, in another form. Almost every library function expects a specific form, and reshaping is how you deliver it.

    Code for this chapter: básico/cap11_reshape.py

    Reshape without changing the data

    The reshape rearranges the same elements into another form. The total needs to remain the same: it never creates or removes elements. And the -1 in one of the dimensions means "calculate yourself":

    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)
    
    Output
    [[ 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)
    

    Five times three equals 15, and the array has 12 elements, so NumPy refuses. The reshape(2, -1) figured out on its own that the second dimension is 6.

    Transpose, flatten, and insert axes

    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)
    
    Output
    (3, 2) (3, 2)
    [0 1 2 3 4 5] [0 1 2 3 4 5]
    (2, 1, 3) (2, 3, 1)
    (3,)
    
    FunctionWhat it does
    a.T or a.transpose()Swaps rows and columns. In more dimensions, it reverses the order of the axes
    a.swapaxes(i, j)Swaps two specific axes
    a.flatten()Flattens to 1D and always copies
    a.ravel()Flattens to 1D and returns a view when possible
    np.newaxis or NoneInserts an axis of size 1
    np.squeeze(a)Removes axes of size 1

    The difference between flatten and ravel is the same as in the previous chapter: one copies, the other shares memory, and changing the result of ravel changes the 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])
    
    Output
    99
    99
    

    The extra axis trick

    Inserting an axis of size 1 is the way to prepare an array for the broadcasting of the next chapter. An array of shape (3,) becomes a column (3, 1) with reshape(-1, 1) or with [:, None]:

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

    A real case: batch of images

    A batch of 10 images of 28 by 28 pixels has shape (10, 28, 28). Many models expect each image as a vector of 784 numbers, that is, shape (10, 784). The -1 calculates the 784 by itself:

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

    reshape returns a view when it can

    The reshape returns a view if memory allows and only copies when there is no other way. Therefore, after a reshape, keep in mind that changing the result can change the original. If in doubt, check with np.shares_memory.

    Exercise 1

    Column and spreadsheet

    Write para_coluna(v) (a 1D vector becomes a column) and lote_para_planilha(imagens) (from (n, h, w) to (n, h*w)).