
- 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 - Performance Optimization with Arrays
Performance Optimization with Arrays
Performance optimization with arrays involves improving the efficiency of operations on arrays, such as reducing computation time and memory usage.
We should optimize performance for the following reasons −
- Speed: Faster computations lead to quicker results and more responsive applications.
- Scalability: Optimized code can handle larger datasets and more complex operations efficiently.
- Resource Efficiency: Reduces memory usage and computational overhead.
Using Vectorized Operations
Vectorized operations refer to the ability to perform operations on entire arrays or matrices in a single step without using explicit loops.
This is achieved through broadcasting and internal optimization, making these operations faster and more efficient.
Example
In the following example, we are performing vectorized addition of two large arrays, "a" and "b", using NumPy's array operations. This operation calculates the element-wise sum of the arrays and stores the result in a new array "c" −
import numpy as np # Create two large arrays a = np.random.rand(1000000) b = np.random.rand(1000000) # Vectorized addition c = a + b print (c)
Following is the output obtained −
[0.91662816 0.65486861 1.60409272 ... 0.95122935 1.12795861 0.15812103]
Utilizing Efficient Data Types
Choosing the appropriate data type for your arrays is important for optimizing performance and memory usage in NumPy.
For example, using np.float32 instead of np.float64 can significantly impact memory usage and performance, particularly when working with large datasets.
In NumPy, a data type (or dtype) defines the kind of elements that an array holds and how much space is required to store each element.
Example
In this example, we are demonstrating the usage of precision change by creating an array with double precision (64-bit) floating-point numbers and then converting it to single precision (32-bit) using the astype() method −
import numpy as np # Create an array with double precision (64-bit) arr_double = np.array([1.0, 2.0, 3.0], dtype=np.float64) # Print the original double precision array print("Original double precision array:") print(arr_double) print("Data type:", arr_double.dtype) # Convert to single precision (32-bit) arr_single = arr_double.astype(np.float32) # Print the converted single precision array print("\nConverted single precision array:") print(arr_single) print("Data type:", arr_single.dtype)
This will produce the following result −
Original double precision array: [1. 2. 3.] Data type: float64 Converted single precision array: [1. 2. 3.] Data type: float32
Avoiding Loops with NumPy Functions
In NumPy, one of the primary advantages is the ability to avoid explicit loops by using built-in functions and array operations. This approach is often referred to as vectorization.
By using NumPy functions, you can perform operations on entire arrays at once, which is more concise compared to using loops.
Example
In the example below, we calculate the mean of the array elements using the np.mean() function, without using any explicit loops −
import numpy as np # Create an array arr = np.array([1, 2, 3, 4, 5]) # Calculate the mean of array elements mean = np.mean(arr) print("mean:",mean)
Following is the output of the above code −
mean: 3.0
Using Broadcasting for Vectorization
Broadcasting refers to the ability to perform element-wise operations on arrays with different shapes. It follows a set of rules to determine how arrays with different shapes can be aligned for operations −
- Same Dimensions: If the arrays have different dimensions, the smaller array's shape is padded with ones on the left until both shapes have the same length.
- Dimension Compatibility: Two dimensions are compatible when they are equal or one of them is 1. For each dimension, if the sizes are different and, if neither of them is 1, then the broadcasting fails.
- Stretching: Arrays with a dimension of size 1 are stretched along that dimension to match the size of the other arrays dimension.
Example
In the following example, we are broadcasting "array_1d" to match the shape of "array_2d", allowing element-wise addition −
import numpy as np # Create a 2D array and a 1D array array_2d = np.array([[1, 2, 3], [4, 5, 6]]) array_1d = np.array([10, 20, 30]) # Add the 1D array to each row of the 2D array result = array_2d + array_1d print(result)
The output obtained is as shown below −
[[11 22 33] [14 25 36]]
In-place Operations for Vectorization
In-place operations in NumPy refer to modifying the data of an array directly, without creating a new array to store the result, saving memory and improving performance.
This is achieved by using operators and functions that alter the content of the original array. These operations generally use operators with an in-place suffix (e.g., +=, -=, *=, /=) or functions that support in-place modification.
Example: Using In-place Operators
In this example, we are applying arithmetic operation "+=" directly on an array without creating a new one −
import numpy as np # Create an array arr = np.array([1, 2, 3, 4, 5]) # Add 10 to each element in-place arr += 10 print(arr)
After executing the above code, we get the following output −
[11 12 13 14 15]
Example: Using In-place Functions
Here, we are calculating the exponential value of each element in an array in-place using NumPy exp() function −
import numpy as np # Create an array with a floating-point data type arr = np.array([1, 2, 3, 4, 5], dtype=np.float64) # Compute the exponential of each element in-place np.exp(arr, out=arr) print(arr)
After executing the above code, we get the following output −
[ 2.71828183 7.3890561 20.08553692 54.59815003 148.4131591 ]
Using Memory Views for Vectorization
Memory views refer to different ways of accessing or viewing the same underlying data in an array without duplicating it. This concept allows you to create different "views" or "slices" of the array that can operate on the same data in various ways −
- Slicing: When you slice an array, NumPy creates a view of the original array, not a copy. This view shares the same data buffer, so changes to the view affect the original array and vice versa.
- Reshaping: Reshaping an array creates a new view of the same data with a different shape. This does not alter the underlying data but changes how it is interpreted.
Example: Slicing
In the example below, we create a 2D NumPy array and a view (slice) of the original array. Modifying the view also affects the original array −
import numpy as np # Create a 2D array arr = np.array([[1, 2, 3], [4, 5, 6]]) # Create a view (slice) of the original array view = arr[:, 1:] # Modify the view view[0, 0] = 99 print(arr)
We get the output as shown below −
[[ 1 99 3] [ 4 5 6]]
Example: Reshaping
Here, we create a 1D NumPy array using the arange() function and then reshape it into a 2D array with 3 rows and 4 columns, changing its structure while preserving the original data −
import numpy as np # Create a 1D array arr = np.arange(12) # Reshape to a 2D array reshaped = arr.reshape((3, 4)) print(reshaped)
We get the output as shown below −
[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]]
Using Strides for Vectorization
Strides are a tuple that indicates the number of bytes to step in each dimension when traversing an array. They determine how array elements are accessed in memory, providing insight into how data is laid out and accessed.
Strides give you the memory offset for each dimension. For instance, in a 2D array, the stride for the second dimension tells you how many bytes to move in memory to access the next element in that row.
Example
In the following example, we create a 2D NumPy array and use the strides attribute to retrieve the number of bytes to step in each dimension when traversing the array −
import numpy as np # Create a 2D array arr = np.array([[1, 2, 3], [4, 5, 6]]) # Print the strides of the array print(arr.strides)
We get the output as shown below −
(24, 8)