# Dimensions and shape {:.no_toc} ## The goal Matrices have dimensions. But how to add and remove extra dimensions (i.e. dimensions with length 1)? Questions to [David Rotermund](mailto:davrot@uni-bremen.de) ## [numpy.ndarray.shape](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html) ```python ndarray.shape ``` > Tuple of array dimensions. > > The shape property is usually used to get the current shape of an array, but may also be used to reshape the array in-place by assigning a tuple of array dimensions to it. As with numpy.reshape, one of the new shape dimensions can be -1, in which case its value is inferred from the size of the array and the remaining dimensions. Reshaping an array in-place will fail if a copy is required. ```python import numpy as np data = np.zeros((2, 4, 2, 7, 2)) print(data.shape) # -> (2, 4, 2, 7, 2) ``` ## Vanishing dimensions ```python import numpy as np data = np.zeros((5, 3, 2)) # All the same dimensionwise print(data.shape) # -> (5, 3, 2) print(data[:].shape) # -> (5, 3, 2) print(data[:, :, :].shape) # -> (5, 3, 2) print(data[...].shape) # -> (5, 3, 2) print(data[0, :, :].shape) # -> (3, 2) print(data[:, 0, :].shape) # -> (5, 2) print(data[:, :, 0].shape) # -> (5, 3) print(data[:, 0, 0].shape) # -> (5,) print(data[0, :, 0].shape) # -> (3,) print(data[0, 0, :].shape) # -> (2,) print(data[0, 0, 0].shape) # -> () print(type(data[0, 0, 0])) # -> ``` ### keepdims There are functions like ```python ndarray.sum(axis=None, dtype=None, out=None, keepdims=False, initial=0, where=True) ndarray.mean(axis=None, dtype=None, out=None, keepdims=False, *, where=True) ndarray.prod(axis=None, dtype=None, out=None, keepdims=False, initial=1, where=True) ndarray.max(axis=None, out=None, keepdims=False, initial=, where=True) ndarray.min(axis=None, out=None, keepdims=False, initial=, where=True) ndarray.argmax(axis=None, out=None, *, keepdims=False) ndarray.argmin(axis=None, out=None, *, keepdims=False) ``` that normally make one dimension vanish. However, often this type of functions have an argument **keepdims** that keeps this dimension alive. ```python import numpy as np data = np.zeros((5, 3, 2)) # All the same dimensionwise print(data.shape) # -> (5, 3, 2) print(data.sum().shape) # -> () print(data.sum(axis=0).shape) # -> (3, 2) print(data.sum(axis=1).shape) # -> (5, 2) print(data.sum(axis=2).shape) # -> (5, 3) # You can use keepdims: print(data.sum(axis=0, keepdims=True).shape) # -> (1, 3, 2) print(data.sum(axis=1, keepdims=True).shape) # -> (5, 1, 2) print(data.sum(axis=2, keepdims=True).shape) # -> (5, 3, 1) ``` As as reminder, shape is only availabe for np.ndarray and torch.Tensor matrices: ```python z = int(7) print(np.array(z).shape) # -> () print(type(np.array(z))) # -> print(type(z)) # -> print(z.shape) # -> AttributeError: 'int' object has no attribute 'shape' ``` ## Stop vanishing dimensions One way to do stop vanishing dimensions is to use slices of thickness 1. If you want the nth element, then use **n:n+1**: ```python import numpy as np data = np.zeros((5, 3, 2)) # All the same dimensionwise print(data.shape) # -> (5, 3, 2) print(data[0:1, :, :].shape) # -> (1, 3, 2) print(data[:, 0:1, :].shape) # -> (5, 1, 2) print(data[:, :, 0:1].shape) # -> (5, 3, 1) print(data[:, 0:1, 0:1].shape) # -> (5, 1, 1) print(data[0:1, :, 0:1].shape) # -> (1, 3, 1) print(data[0:1, 0:1, :].shape) # -> (1, 1, 2) print(data[0:1, 0:1, 0:1].shape) # -> (1, 1, 1) print(type(data[0:1, 0:1, 0:1])) # -> ``` **Please understand this creates a view which is connected to original data.** If necessary make a **copy()**. ## Adding dimensions with [np.newaxis](https://numpy.org/doc/stable/reference/constants.html#numpy.newaxis) ```python numpy.newaxis ``` > A convenient alias for None, useful for indexing arrays. ```python import numpy as np data = np.zeros((2)) print(data.shape) # -> (2,) print(data[:, np.newaxis].shape) # -> (2, 1) print(data[np.newaxis, :].shape) # -> (1, 2) print(data[:, np.newaxis, np.newaxis].shape) # -> (2, 1, 1) print(data[np.newaxis, :, np.newaxis].shape) # -> (1, 2, 1) print(data[:, np.newaxis, np.newaxis].shape) # -> (2, 1, 1) ``` ## Adding dimensions with [numpy.expand_dims](https://numpy.org/doc/stable/reference/generated/numpy.expand_dims.html) In the case you don’t like newaxis for adding a new dimension...​ ```python numpy.expand_dims(a, axis) ``` > Expand the shape of an array. > > Insert a new axis that will appear at the axis position in the expanded array shape. ```python import numpy as np data = np.zeros((2)) print(data.shape) # -> (2,) print(np.expand_dims(data, axis=0).shape) # -> (1, 2) print(np.expand_dims(data, axis=1).shape) # -> (2, 1) print(np.expand_dims(data, axis=(1, 2, 3)).shape) # -> (2, 1, 1, 1) ``` ## Removing dimensions with [numpy.squeeze](https://numpy.org/doc/stable/reference/generated/numpy.squeeze.html) ```python numpy.squeeze(a, axis=None) ``` > Remove axes of length one from a. ```python import numpy as np data = np.zeros((1, 2, 1, 1)) print(data.shape) # -> (1, 2, 1, 1) print(np.squeeze(data).shape) # -> (2,) print(np.squeeze(data, axis=0).shape) # -> (2, 1, 1) print(np.squeeze(data, axis=2).shape) # -> (1, 2, 1) print(np.squeeze(data, axis=3).shape) # -> (1, 2, 1) print(np.squeeze(data, axis=(0, -1)).shape) # -> (2, 1) print( np.squeeze(data, axis=1).shape ) # -> ValueError: cannot select an axis to squeeze out which has size not equal to one ```