
- NumPy - Home
- NumPy - Introduction
- NumPy - Environment
- NumPy Arrays
- NumPy - Ndarray Object
- NumPy - Data Types
- NumPy Creating and Manipulating Arrays
- NumPy - Array Creation Routines
- NumPy - Array Manipulation
- NumPy - Array from Existing Data
- NumPy - Array From Numerical Ranges
- NumPy - Iterating Over Array
- NumPy - Reshaping Arrays
- NumPy - Concatenating Arrays
- NumPy - Stacking Arrays
- NumPy - Splitting Arrays
- NumPy - Flattening Arrays
- NumPy - Transposing Arrays
- NumPy Indexing & Slicing
- NumPy - Indexing & Slicing
- NumPy - Indexing
- NumPy - Slicing
- NumPy - Advanced Indexing
- NumPy - Fancy Indexing
- NumPy - Field Access
- NumPy - Slicing with Boolean Arrays
- NumPy Array Attributes & Operations
- NumPy - Array Attributes
- NumPy - Array Shape
- NumPy - Array Size
- NumPy - Array Strides
- NumPy - Array Itemsize
- NumPy - Broadcasting
- NumPy - Arithmetic Operations
- NumPy - Array Addition
- NumPy - Array Subtraction
- NumPy - Array Multiplication
- NumPy - Array Division
- NumPy Advanced Array Operations
- NumPy - Swapping Axes of Arrays
- NumPy - Byte Swapping
- NumPy - Copies & Views
- NumPy - Element-wise Array Comparisons
- NumPy - Filtering Arrays
- NumPy - Joining Arrays
- NumPy - Sort, Search & Counting Functions
- NumPy - Searching Arrays
- NumPy - Union of Arrays
- NumPy - Finding Unique Rows
- NumPy - Creating Datetime Arrays
- NumPy - Binary Operators
- NumPy - String Functions
- NumPy - Matrix Library
- NumPy - Linear Algebra
- NumPy - Matplotlib
- NumPy - Histogram Using Matplotlib
- NumPy Sorting and Advanced Manipulation
- NumPy - Sorting Arrays
- NumPy - Sorting along an axis
- NumPy - Sorting with Fancy Indexing
- NumPy - Structured Arrays
- NumPy - Creating Structured Arrays
- NumPy - Manipulating Structured Arrays
- NumPy - Record Arrays
- Numpy - Loading Arrays
- Numpy - Saving Arrays
- NumPy - Append Values to an Array
- NumPy - Swap Columns of Array
- NumPy - Insert Axes to an Array
- NumPy Handling Missing Data
- NumPy - Handling Missing Data
- NumPy - Identifying Missing Values
- NumPy - Removing Missing Data
- NumPy - Imputing Missing Data
- NumPy Performance Optimization
- NumPy - Performance Optimization with Arrays
- NumPy - Vectorization with Arrays
- NumPy - Memory Layout of Arrays
- Numpy Linear Algebra
- NumPy - Linear Algebra
- NumPy - Matrix Library
- NumPy - Matrix Addition
- NumPy - Matrix Subtraction
- NumPy - Matrix Multiplication
- NumPy - Element-wise Matrix Operations
- NumPy - Dot Product
- NumPy - Matrix Inversion
- NumPy - Determinant Calculation
- NumPy - Eigenvalues
- NumPy - Eigenvectors
- NumPy - Singular Value Decomposition
- NumPy - Solving Linear Equations
- NumPy - Matrix Norms
- NumPy Element-wise Matrix Operations
- NumPy - Sum
- NumPy - Mean
- NumPy - Median
- NumPy - Min
- NumPy - Max
- NumPy Set Operations
- NumPy - Unique Elements
- NumPy - Intersection
- NumPy - Union
- NumPy - Difference
- NumPy Random Number Generation
- NumPy - Random Generator
- NumPy - Permutations & Shuffling
- NumPy - Uniform distribution
- NumPy - Normal distribution
- NumPy - Binomial distribution
- NumPy - Poisson distribution
- NumPy - Exponential distribution
- NumPy - Rayleigh Distribution
- NumPy - Logistic Distribution
- NumPy - Pareto Distribution
- NumPy - Visualize Distributions With Sea born
- NumPy - Matplotlib
- NumPy - Multinomial Distribution
- NumPy - Chi Square Distribution
- NumPy - Zipf Distribution
- NumPy File Input & Output
- NumPy - I/O with NumPy
- NumPy - Reading Data from Files
- NumPy - Writing Data to Files
- NumPy - File Formats Supported
- NumPy Mathematical Functions
- NumPy - Mathematical Functions
- NumPy - Trigonometric functions
- NumPy - Exponential Functions
- NumPy - Logarithmic Functions
- NumPy - Hyperbolic functions
- NumPy - Rounding functions
- NumPy Fourier Transforms
- NumPy - Discrete Fourier Transform (DFT)
- NumPy - Fast Fourier Transform (FFT)
- NumPy - Inverse Fourier Transform
- NumPy - Fourier Series and Transforms
- NumPy - Signal Processing Applications
- NumPy - Convolution
- NumPy Polynomials
- NumPy - Polynomial Representation
- NumPy - Polynomial Operations
- NumPy - Finding Roots of Polynomials
- NumPy - Evaluating Polynomials
- NumPy Statistics
- NumPy - Statistical Functions
- NumPy - Descriptive Statistics
- NumPy Datetime
- NumPy - Basics of Date and Time
- NumPy - Representing Date & Time
- NumPy - Date & Time Arithmetic
- NumPy - Indexing with Datetime
- NumPy - Time Zone Handling
- NumPy - Time Series Analysis
- NumPy - Working with Time Deltas
- NumPy - Handling Leap Seconds
- NumPy - Vectorized Operations with Datetimes
- NumPy ufunc
- NumPy - ufunc Introduction
- NumPy - Creating Universal Functions (ufunc)
- NumPy - Arithmetic Universal Function (ufunc)
- NumPy - Rounding Decimal ufunc
- NumPy - Logarithmic Universal Function (ufunc)
- NumPy - Summation Universal Function (ufunc)
- NumPy - Product Universal Function (ufunc)
- NumPy - Difference Universal Function (ufunc)
- NumPy - Finding LCM with ufunc
- NumPy - ufunc Finding GCD
- NumPy - ufunc Trigonometric
- NumPy - Hyperbolic ufunc
- NumPy - Set Operations ufunc
- NumPy Useful Resources
- NumPy - Quick Guide
- NumPy - Cheatsheet
- NumPy - Useful Resources
- NumPy - Discussion
- NumPy Compiler
NumPy - Copies & Views
In NumPy, when you perform operations on arrays, the result might be a copy of the original data or just a view of the original data. Understanding the difference between these two is important for efficient memory management and avoiding unintended side effects in your code.
Creating Copies in NumPy
We can create a copy of an array explicitly in NumPy using the copy() function. This function generates a new array and copies the data from the original array into this new array.
When you create a copy of an array in NumPy, the data is fully duplicated. This means that changes made to the copy do not affect the original array, and vice versa. Copies are useful when you need to work with a modified version of an array without altering the original data.
Example
In the following example, modifying copied_array does not affect original_array, demonstrating the independence of the two arrays −
import numpy as np # Original array original_array = np.array([1, 2, 3]) # Creating a copy copied_array = original_array.copy() # Modifying the copy copied_array[0] = 10 print("Original Array:", original_array) print("Copied Array:", copied_array)
Following is the output obtained −
Original Array: [1 2 3] Copied Array: [10 2 3]
Shallow Copy Vs. Deep Copy
In the context of NumPy arrays, the difference between shallow and deep copies is important for understanding how data is handled when copied.
Shallow Copy
A shallow copy of an array creates a new array object, but it does not create copies of the elements contained within the original array if those elements themselves are arrays or other complex objects.
Instead, the new array still references the same elements as the original array. This means that changes to the contents of the elements will affect both the original and the copied array.
- Array-Level Copy − In the case of NumPy arrays, a shallow copy means that while the top-level array object is duplicated, the underlying data buffer is not copied. The new array is simply a new view of the same data.
- Usage − Shallow copies are useful when you need a new array object but want to avoid the overhead of duplicating large amounts of data.
Example
In this example, modifying shallow_copy also modifies original_array because they share the same underlying data −
import numpy as np # Original array original_array = np.array([[1, 2, 3], [4, 5, 6]]) # Shallow copy shallow_copy = original_array.view() # Modify an element in the shallow copy shallow_copy[0, 0] = 100 print("Original Array:") print(original_array) print("\nShallow Copy:") print(shallow_copy)
This will produce the following result −
Original Array: [[100 2 3] [ 4 5 6]] Shallow Copy: [[100 2 3] [ 4 5 6]]
Deep Copy
A deep copy, on the other hand, creates a new array object along with copies of all the data it contains. This means that any changes made to the new array will not affect the original array, and vice versa. The data in the new array is completely independent of the data in the original array.
- Full Duplication − In the context of NumPy, a deep copy involves duplicating the entire data buffer of the array, ensuring that the new array is entirely separate from the original.
- Usage − Deep copies are important when you need to work with data independently of the original array, especially when the data may be modified in a way that should not impact the original.
Example
In this case, modifying deep_copy does not affect original_array demonstrating the independence of the two arrays −
import numpy as np # Original array original_array = np.array([[1, 2, 3], [4, 5, 6]]) # Deep copy deep_copy = original_array.copy() # Modify an element in the deep copy deep_copy[0, 0] = 100 print("Original Array:") print(original_array) print("\nDeep Copy:") print(deep_copy)
Following is the output of the above code −
Original Array: [[1 2 3] [4 5 6]] Deep Copy: [[100 2 3] [ 4 5 6]]
Copying Subarrays
To avoid modifying the original array when working with a subarray, you should create a copy of the subarray. This is useful when you need to manipulate or analyze the subarray independently of the original data.
A subarray is simply a portion of an existing NumPy array. You can extract subarrays using slicing techniques.
For example, if you have a 2D array, you can extract a smaller 2D subarray by slicing along its rows and columns. However, by default, slicing creates a view of the original array, not a separate copy. This means that changes to the subarray will also affect the original array unless you explicitly create a copy.
Example
In the example below, sub_array is a completely independent array due to the use of copy() function −
import numpy as np # Original 2D array original_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # Creating a copy of the subarray sub_array = original_array[0:2].copy() sub_array[0] = 20 print("Original Array after subarray copy:", original_array) print("Subarray:", sub_array)
The output obtained is as shown below −
Original Array after subarray copy: [[1 2 3] [4 5 6] [7 8 9]] Subarray: [[20 20 20] [ 4 5 6]]
Creating Views in NumPy
Views are created when you slice an array or perform certain operations like reshaping. The data is not copied; instead, the new array is just a different way of viewing the original data.
In other words, a view is a new array object that looks at the same data as the original array. This means that if you modify the view, the changes will be reflected in the original array, and vice versa.
Example
In this example, modifying view_array directly affects original_array, showing that they share the same data −
import numpy as np # Original array original_array = np.array([1, 2, 3]) view_array = original_array[0:2] # Modifying the view view_array[0] = 30 print("Original Array after view modification:", original_array) print("View Array:", view_array)
After executing the above code, we get the following output −
Original Array after view modification: [30 2 3] View Array: [30 2]
When Views are Returned?
Not all slicing or operations result in a view. If the memory layout of the array changes, NumPy might return a copy instead of a view.
Views from Slicing
The most common scenario where views are returned in NumPy is when you slice an array. Slicing is a way to extract a portion of an array by specifying a range of indices. Instead of creating a new array with its own data, NumPy returns a view, meaning the sliced array shares the same data as the original array.
Example
In this example, view_array is a view of original_array. The data is not copied, and both arrays share the same underlying memory. This means that any changes made to "view_array" will also affect "original_array" −
import numpy as np # Original array original_array = np.array([1, 2, 3, 4, 5]) # Creating a view by slicing the original array view_array = original_array[1:4] print("Original Array:") print(original_array) print("\nView Array (Sliced):") print(view_array)
The result produced is as follows −
Original Array: [1 2 3 4 5] View Array (Sliced): [2 3 4]
Views from Reshaping
Another common scenario where views are returned is when you reshape an array. Reshaping changes the shape of the array (i.e., the number of elements in each dimension) without altering the underlying data. When possible, NumPy returns a view of the original array in the new shape.
Example
Here, reshaped_array is a view of original_array, simply presented in a "2x3" format. The data remains the same, and modifying the "reshaped_array" will also modify the "original_array" −
import numpy as np # Original 1D array original_array = np.array([1, 2, 3, 4, 5, 6]) # Reshaping the array into a 2x3 matrix reshaped_array = original_array.reshape(2, 3) print("Original Array:") print(original_array) print("\nReshaped Array (View):") print(reshaped_array)
We get the output as shown below −
Original Array:[1 2 3 4 5 6] Reshaped Array (View): [[1 2 3] [4 5 6]]
Views from Transposing
Transposing an array involves flipping it over its diagonal, converting rows to columns and vice versa. When you transpose an array using functions like np.transpose() or the .T attribute, NumPy returns a view, not a copy, whenever possible.
Example
In this case, transposed_array is a view of original_array, but with the axes swapped. The underlying data remains the same, and changes to "transposed_array" will reflect in "original_array" −
import numpy as np # Original 2D array original_array = np.array([[1, 2, 3], [4, 5, 6]]) # Transposing the array transposed_array = original_array.T print("Original Array:") print(original_array) print("\nTransposed Array (View):") print(transposed_array)
Following is the output obtained −
Original Array: [[1 2 3] [4 5 6]] Transposed Array (View): [[1 4] [2 5] [3 6]]
The Base Attribute
In NumPy, the base attribute of an array examines whether the array is a view or a copy of another array. It is a reference to the original array from which the current array was derived.
If the current array is a view of another array, "base" will point to that original array. If the current array is not a view (i.e., it is either the original array or a deep copy), "base" will be None.
Example: Base Attribute of an Original Array
When you create an array, its base attribute will be None because it is the original array −
import numpy as np # Creating an original array original_array = np.array([10, 20, 30, 40, 50]) # Checking the base attribute print("Base of original array:", original_array.base)
This will produce the following result −
Base of original array: None
Example: Base Attribute of a View
When you create a view of an array (for example, by slicing), the base attribute of the view will point to the original array −
import numpy as np # Creating an original array original_array = np.array([10, 20, 30, 40, 50]) # Creating a view of the original array view_array = original_array[1:4] # Checking the base attribute print("Base of view array:", view_array.base)
Following is the output of the above code −
Base of view array: [10 20 30 40 50]
Example: Base Attribute of a Copy
If you create a copy of an array, the base attribute will be None, indicating that the copied array is independent of the original −
import numpy as np # Creating an original array original_array = np.array([10, 20, 30, 40, 50]) # Creating a copy of the original array copy_array = original_array.copy() # Checking the base attribute print("Base of copy array:", copy_array.base)
Following is the output of the above code −
Base of copy array: None