diff options
Diffstat (limited to 'doc/source/user/basics.copies.rst')
-rw-r--r-- | doc/source/user/basics.copies.rst | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/doc/source/user/basics.copies.rst b/doc/source/user/basics.copies.rst new file mode 100644 index 000000000..49fdb85b1 --- /dev/null +++ b/doc/source/user/basics.copies.rst @@ -0,0 +1,135 @@ +.. _basics.copies-and-views: + +**************** +Copies and views +**************** + +The NumPy array is a contiguous block of memory consisting of two parts- the +data buffer with the actual data elements and the metadata which contains +information about the data buffer. The metadata includes data type, strides +and other important information that helps manipulate the :class:`.ndarray` +easily. See the :ref:`organization-numpy-arrays` section for a detailed look. + +View or shallow copy +==================== + +It is possible to perceive the array differently by changing the +metadata. These new arrays are called views or shallow copies. The data buffer +remains the same so any changes made to a view reflects in the original +copy. A view can be forced through the :meth:`.ndarray.view` method. + + +Copy or deep copy +================= + +When a new array is created by duplicating the data buffer as well as the +metadata, it is called a copy or a deep copy. Changes made to the copy +do not reflect on the original array. Making a copy is slower and memory +consuming but sometimes necessary. A copy can be forced by using +:meth:`.ndarray.copy`. + + +How to tell if the array is a view or a copy +============================================ + +The :attr:`base <.ndarray.base>` attribute of the ndarray makes it easy +to tell if an array is a view or a copy. The base attribute of a view returns +the original array while for a copy it returns ``None``. + + >>> x = np.arange(9) + >>> x + array([0, 1, 2, 3, 4, 5, 6, 7, 8]) + >>> y = x.reshape(3, 3) + >>> y + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> y.base # .reshape() creates a view + array([0, 1, 2, 3, 4, 5, 6, 7, 8]) + >>> z = y[[2, 1]] + >>> z + array([[6, 7, 8], + [3, 4, 5]]) + >>> z.base is None # advanced indexing creates a copy + True + +Indexing operations +=================== + +Views are created when elements can be addressed with offsets, strides, +and counts in the original array. Hence, basic indexing always creates views. +For example:: + + >>> x = np.arange(10) + >>> x + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> y = x[1:3] # creates a view + >>> y + array([1, 2]) + >>> x[1:3] = [10, 11] + >>> x + array([ 0, 10, 11, 3, 4, 5, 6, 7, 8, 9]) + >>> y + array([10, 11]) + +Here ``y`` gets changed when ``x`` is changed because it is a view. + +Advanced indexing, on the other hand, always creates copies. For example:: + + >>> x = np.arange(9).reshape(3, 3) + >>> x + array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + >>> y = x[[1, 2]] + >>> y + array([[3, 4, 5], + [6, 7, 8]]) + >>> y.base is None + True + +Here, ``y`` is a copy as signified by the base attribute. We can also +confirm this by assigning new values to ``x[[1, 2]]`` which in turn +will not affect ``y`` at all:: + + >>> x[[1, 2]] = [[10, 11, 12], [13, 14, 15]] + >>> x + array([[ 0, 1, 2], + [10, 11, 12], + [13, 14, 15]]) + >>> y + array([[3, 4, 5], + [6, 7, 8]]) + +It must be noted here that during the assignment of ``x[[1, 2]]`` no view +or copy is created as the assignment happens in-place. + + +Other operations +================ + +The :func:`numpy.reshape` function creates a view where possible or a copy +otherwise. In most cases, the strides can be modified to reshape the +array with a view. However, in some cases where the array becomes +non-contiguous (perhaps after a :meth:`.ndarray.transpose` operation), +the reshaping cannot be done by modifying strides and requires a copy. +In these cases, we can raise an error by assigning the new shape to the +shape attribute of the array. For example:: + + >>> x = np.ones((2, 3)) + >>> y = x.T # makes the array non-contiguous + >>> y + array([[1., 1.], + [1., 1.], + [1., 1.]]) + >>> z = y.view() + >>> z.shape = 6 + AttributeError: Incompatible shape for in-place modification. + Use `.reshape()` to make a copy with the desired shape. + +:func:`.ravel` returns a contiguous flattened view of the array +wherever possible. On the other hand, :meth:`.ndarray.flatten` always returns +a flattened copy of the array. However, to guarantee a view in most cases +``x.reshape(-1)`` may be preferable. + + |