44Copies and views
55****************
66
7- When operating on a NumPy array, we can sometimes improve performance by using
8- :term: `views <view> ` instead of copies of the array. However, when handling
9- large amounts of important data, it can be risky to directly operate on it and
10- it could be safer to use copies. Hence, it is important to know the difference
11- between these two terms to correctly determine when to use which one.
12-
13- The NumPy array is a :term: `contiguous ` block of memory consisting of two parts:
14- the data buffer with the actual data elements, and the metadata which contains
15- information about the data buffer. The metadata includes data type, strides
16- and other important information that helps manipulate the :class: `.ndarray `
17- easily. See the :ref: `numpy-internals ` section for a detailed look.
18-
19- View or shallow copy
20- ====================
21-
22- It is possible to access the array differently by just changing the
23- metadata and without changing the data buffer. This creates a new way of
24- looking at the data and these new arrays are called views or shallow copies.
25- The data buffer remains the same so any changes made to a view reflects in the
26- original copy. A view can be forced through the :meth: `.ndarray.view ` method.
27-
28-
29- Copy or deep copy
30- =================
7+ When operating on NumPy arrays, it is possible to access the internal data
8+ buffer directly using a :ref: `view <view >` without copying data around. This
9+ ensures good performance but can also cause unwanted problems if the user is
10+ not aware of how this works. Hence, it is important to know the difference
11+ between these two terms and to know which operations return copies and
12+ which return views.
13+
14+ The NumPy array is a data structure consisting of two parts:
15+ the :term: `contiguous ` data buffer with the actual data elements and the
16+ metadata that contains information about the data buffer. The metadata
17+ includes data type, strides, and other important information that helps
18+ manipulate the :class: `.ndarray ` easily. See the :ref: `numpy-internals `
19+ section for a detailed look.
20+
21+ .. _view :
22+
23+ View
24+ ====
25+
26+ It is possible to access the array differently by just changing certain
27+ metadata like :term: `stride ` and :term: `dtype ` without changing the
28+ data buffer. This creates a new way of looking at the data and these new
29+ arrays are called views. The data buffer remains the same, so any changes made
30+ to a view reflects in the original copy. A view can be forced through the
31+ :meth: `.ndarray.view ` method.
32+
33+ Copy
34+ ====
3135
3236When a new array is created by duplicating the data buffer as well as the
33- metadata, it is called a copy or a deep copy . Changes made to the copy
34- do not reflect on the original array. Making a copy is slower and memory
35- consuming but sometimes necessary. A copy can be forced by using
37+ metadata, it is called a copy. Changes made to the copy
38+ do not reflect on the original array. Making a copy is slower and
39+ memory- consuming but sometimes necessary. A copy can be forced by using
3640:meth: `.ndarray.copy `.
3741
38-
39- How to tell if the array is a view or a copy
40- ============================================
41-
42- The :attr: `base <.ndarray.base> ` attribute of the ndarray makes it easy
43- to tell if an array is a view or a copy. The base attribute of a view returns
44- the original array while for a copy it returns ``None ``.
45-
46- >>> x = np.arange(9 )
47- >>> x
48- array([0, 1, 2, 3, 4, 5, 6, 7, 8])
49- >>> y = x.reshape(3 , 3 )
50- >>> y
51- array([[0, 1, 2],
52- [3, 4, 5],
53- [6, 7, 8]])
54- >>> y.base # .reshape() creates a view
55- array([0, 1, 2, 3, 4, 5, 6, 7, 8])
56- >>> z = y[[2 , 1 ]]
57- >>> z
58- array([[6, 7, 8],
59- [3, 4, 5]])
60- >>> z.base is None # advanced indexing creates a copy
61- True
62-
6342Indexing operations
6443===================
6544
45+ .. seealso :: :ref:`basics.indexing`
46+
6647Views are created when elements can be addressed with offsets and strides
6748in the original array. Hence, basic indexing always creates views.
6849For example::
@@ -79,9 +60,10 @@ For example::
7960 >>> y
8061 array([10, 11])
8162
82- Here ``y `` gets changed when ``x `` is changed because it is a view.
63+ Here, ``y `` gets changed when ``x `` is changed because it is a view.
8364
84- Advanced indexing, on the other hand, always creates copies. For example::
65+ :ref: `advanced-indexing `, on the other hand, always creates copies.
66+ For example::
8567
8668 >>> x = np.arange(9).reshape(3, 3)
8769 >>> x
@@ -95,9 +77,9 @@ Advanced indexing, on the other hand, always creates copies. For example::
9577 >>> y.base is None
9678 True
9779
98- Here, ``y `` is a copy as signified by the base attribute. We can also
99- confirm this by assigning new values to ``x[[1, 2]] `` which in turn
100- will not affect ``y `` at all::
80+ Here, ``y `` is a copy, as signified by the :attr: ` base <.ndarray.base> `
81+ attribute. We can also confirm this by assigning new values to ``x[[1, 2]] ``
82+ which in turn will not affect ``y `` at all::
10183
10284 >>> x[[1, 2]] = [[10, 11, 12], [13, 14, 15]]
10385 >>> x
@@ -139,6 +121,28 @@ shape attribute of the array. For example::
139121Taking the example of another operation, :func: `.ravel ` returns a contiguous
140122flattened view of the array wherever possible. On the other hand,
141123:meth: `.ndarray.flatten ` always returns a flattened copy of the array.
142- However, to guarantee a view in most cases ``x.reshape(-1) `` may be preferable.
124+ However, to guarantee a view in most cases, ``x.reshape(-1) `` may be preferable.
143125
126+ How to tell if the array is a view or a copy
127+ ============================================
144128
129+ The :attr: `base <.ndarray.base> ` attribute of the ndarray makes it easy
130+ to tell if an array is a view or a copy. The base attribute of a view returns
131+ the original array while it returns ``None `` for a copy.
132+
133+ >>> x = np.arange(9 )
134+ >>> x
135+ array([0, 1, 2, 3, 4, 5, 6, 7, 8])
136+ >>> y = x.reshape(3 , 3 )
137+ >>> y
138+ array([[0, 1, 2],
139+ [3, 4, 5],
140+ [6, 7, 8]])
141+ >>> y.base # .reshape() creates a view
142+ array([0, 1, 2, 3, 4, 5, 6, 7, 8])
143+ >>> z = y[[2 , 1 ]]
144+ >>> z
145+ array([[6, 7, 8],
146+ [3, 4, 5]])
147+ >>> z.base is None # advanced indexing creates a copy
148+ True
0 commit comments