numpy
numpy
NumPy is a fundamental package for numerical computing in Python. It provides support for
multidimensional arrays and matrices, along with a collection of mathematical functions to operate
on these arrays efficiently. Key features of NumPy include:
2. Efficient Operations: NumPy provides a wide range of mathematical functions that operate
element-wise on arrays, enabling efficient numerical computations.
4. Indexing and Slicing: NumPy offers powerful indexing and slicing capabilities for accessing
and modifying elements within arrays, including advanced techniques like boolean indexing
and fancy indexing.
5. Integration with Other Libraries: NumPy is the foundation for many other scientific
computing libraries in Python, such as SciPy, Matplotlib, and scikit-learn. It seamlessly
integrates with these libraries, providing a cohesive ecosystem for scientific computing.
Importing NumPy:
import numpy as np
1. Functionality:
NumPy arrays: NumPy arrays are homogeneous, meaning all elements in the array are
of the same data type. They support a wide range of mathematical operations and
functions, such as element-wise operations, linear algebra, Fourier transforms, random
number generation, and more. NumPy also provides advanced indexing and slicing
capabilities.
Python lists: Python lists can contain elements of different data types, making them
heterogeneous. They offer basic functionality for iterating over elements, appending,
inserting, and removing elements, but they lack specialized mathematical operations.
2. Performance:
NumPy arrays: NumPy arrays are highly optimized for numerical operations and are
implemented in C, which makes them significantly faster than Python lists for numerical
computations, especially when working with large datasets.
Python lists: Python lists are implemented in Python itself, which can lead to slower
performance compared to NumPy arrays, particularly for numerical computations
involving large datasets.
3. Memory Usage:
NumPy arrays: NumPy arrays typically use less memory compared to Python lists,
especially for large datasets, because they store data in a contiguous block of memory
and can take advantage of data type optimizations.
Python lists: Python lists can potentially use more memory compared to NumPy arrays
due to the overhead of storing additional information about each element (e.g., type
information, reference count).
4. Ease of Use:
NumPy arrays: NumPy arrays offer a wide range of functions and methods specifically
designed for numerical computing tasks, making them convenient to use for scientific
and mathematical applications.
Python lists: Python lists are more general-purpose and flexible, making them easier to
work with for tasks that do not involve numerical computations or require
heterogeneous data types.
import sys
# Time how long it takes to sum the list and the array
import time
# Print the time it took to sum the list and the array
print(f"Time to sum list: {list_sum_time:.2f} milliseconds")
print(f"Time to sum array: {array_sum_time:.2f} milliseconds")
np.arange() is a function in NumPy used to create an array with regularly spaced values within a
specified range. Its syntax is:
[0 1 2 3 4 5 6 7 8 9]
NumPy arrays, or ndarrays, are the primary data structure used in NumPy. They are homogeneous
collections of elements with fixed dimensions and have many similarities to Python lists but with
additional functionality optimized for numerical computing.
1D Arrays:
1D arrays are like traditional arrays or lists. They have a single row and can be indexed using a
single index.
# Create a 1D array
arr_1d = np.array([1, 2, 3, 4, 5])
print(arr_1d) # Output: [1 2 3 4 5]
print(arr_1d[0]) # Output: 1
[1 2 3 4 5]
1
2D Arrays:
2D arrays, also known as matrices, have rows and columns. They are indexed using two indices,
one for the row and one for the column.
# Create a 2D array
arr_2d = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(arr_2d)
[[1 2 3]
[4 5 6]
[7 8 9]]
# Create a 2D array
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
The data type of an ndarray specifies the type of elements stored in the array. NumPy arrays can
hold elements of different types such as integers, floats, booleans, etc.
3. Size:
The size of an ndarray is the total number of elements in the array. It is equal to the product of the
dimensions of the array.
# Create a 3D array
arr_3d = np.zeros((2, 3, 4))
print(arr_3d)
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]]
float64
Size of the array: 24
The ndim attribute of an ndarray specifies the number of dimensions or axes of the array.
# Create a 4D array
arr_4d = np.ones((2, 3, 4, 5))
[[[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]]
[[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]]]
Number of dimensions: 4
5. Itemsize:
The itemsize attribute of an ndarray specifies the size of each element in bytes.
int64
Size of each element (in bytes): 8
Double-click (or enter) to edit
NumPy provides a variety of data types to represent different kinds of numerical data. These data
types are important for controlling memory usage and ensuring data integrity in numerical
computations.
You can specify the data type of an ndarray using the dtype parameter of NumPy functions or by
providing the data type as an argument to the array creation functions.
Precision:
Precision refers to the level of detail and accuracy with which numerical values are represented.
NumPy data types have different levels of precision, which determine the range of values they can
represent and the amount of memory they occupy.
# In this example, the `int32` data type has limited precision compared to `int64`, which ca
np.zeros creates an array filled with zeros. It takes the shape of the desired array as input and
returns an array of that shape filled with zeros.
Syntax:
numpy.zeros(shape, dtype=float)
[[0. 0. 0.]
[0. 0. 0.]]
np.ones:
np.ones creates an array filled with ones. Similar to np.zeros , it takes the shape of the desired
array as input and returns an array of that shape filled with ones.
Syntax:
numpy.ones(shape, dtype=None)
[[1. 1.]
[1. 1.]
[1. 1.]]
np.full:
np.full creates an array filled with a specified constant value. It takes the shape of the desired
array and the constant value as input and returns an array of that shape filled with the specified
value.
Syntax:
[[4.5 4.5]
[4.5 4.5]]
# Addition
arr_sum = np.add([1, 2, 3], [4, 5, 6])
print("Addition:", arr_sum) # Output: [5 7 9]
# Subtraction
arr_diff = np.subtract([5, 6, 7], [2, 3, 1])
print("Subtraction:", arr_diff) # Output: [3 3 6]
# Multiplication
arr_prod = np.multiply([2, 3, 4], [3, 4, 5])
print("Multiplication:", arr_prod) # Output: [ 6 12 20]
# Division
arr_div = np.divide([10, 12, 14], [2, 3, 2])
print("Division:", arr_div) # Output: [5. 4. 7.]
# Modulus
arr_mod = np.mod([10, 11, 12], [3, 4, 5])
print("Modulus:", arr_mod) # Output: [1 3 2]
# Exponentiation
arr_pow = np.power([2, 3, 4], [2, 3, 2])
print("Exponentiation:", arr_pow) # Output: [ 4 27 16]
Addition: [5 7 9]
Subtraction: [3 3 6]
Multiplication: [ 6 12 20]
Division: [5. 4. 7.]
Modulus: [1 3 2]
Exponentiation: [ 4 27 16]
2. Relational Operations:
# Create sample arrays
arr1 = np.array([1, 2, 3, 4])
arr2 = np.array([2, 2, 4, 3])
# Equal
print("Equal:", arr1 == arr2) # Output: [False True False False]
# Not Equal
print("Not Equal:", arr1 != arr2) # Output: [ True False True True]
# Greater Than
print("Greater Than:", arr1 > arr2) # Output: [False False False True]
# Less Than
print("Less Than:", arr1 < arr2) # Output: [ True False False False]
Indexing refers to accessing individual elements of an array using their position (index) within the
array. In NumPy, indexing starts from 0, so the first element has index 0, the second element has
index 1, and so on.
# Create a 1D array
arr = np.array([1, 2, 3, 4, 5])
First element: 1
Second element: 2
Last element: 5
2. Slicing:
Slicing allows you to extract a subset of elements from an array by specifying a range of indices.
The basic syntax for slicing is start:stop:step , where start is the starting index (inclusive),
stop is the ending index (exclusive), and step is the step size.
# Create a 1D array
arr = np.array([1, 2, 3, 4, 5])
Slice: [2 3]
Slice with step: [1 3]
3. Negative Indexing:
Negative indexing allows you to access elements from the end of the array by specifying negative
indices. -1 refers to the last element, -2 refers to the second last element, and so on.
# Create a 1D array
arr = np.array([1, 2, 3, 4, 5])
Last element: 5
You can omit any of the slicing parameters to use default values. Omitting start defaults to 0,
omitting stop defaults to the end of the array, and omitting step defaults to 1.
# Create a 1D array
arr = np.array([1, 2, 3, 4, 5])
Indexing refers to accessing individual elements of an array using their position (index) within the
array. In a 2D array, indexing is done using row and column indices.
# Create a 2D array
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
2. Slicing:
Slicing allows you to extract a subset of elements from an array by specifying ranges of row and
column indices. The basic syntax for slicing is start:stop:step , where start is the starting
index (inclusive), stop is the ending index (exclusive), and step is the step size.
# Create a 2D array
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# Modify slice
arr[0:2, 1:3] = [[10, 20], [30, 40]]
print("Modified array after slicing:", arr)
Slice: [[2 3]
[5 6]]
Modified array after slicing: [[ 1 10 20]
[ 4 30 40]
[ 7 8 9]]
3. Negative Indexing:
Negative indexing can also be used in 2D arrays to access elements from the end of the array.
# Create a 2D array
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
Last element: 9
You can omit any of the slicing parameters to use default values. Omitting start defaults to 0,
omitting stop defaults to the end of the array, and omitting step defaults to 1.
# Create a 2D array
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# Slice elements from all rows and columns 0 to 1 (exclusive) with step size 2
print("Slice with omitted step:", arr[:, 0:2:2])
Boolean indexing allows you to select elements from an array based on a condition. You create a
boolean mask indicating which elements satisfy the condition, and then use this mask to extract
the desired elements.
# Create a 1D array
arr_1d = np.array([1, 2, 3, 4, 5])
Selected elements: [4 5]
# Create a 2D array
arr_2d = np.array([[1, 2, 3], # False, False, True
[4, 5, 6],
[7, 8, 9]])
2. Fancy Indexing:
Fancy indexing allows you to select elements from an array using arrays of indices. You provide
arrays of indices along each axis, and the elements at those indices are returned as a new array.
# Create a 1D array
arr_1d = np.array([1, 2, 3, 4, 5])
# Fancy indexing
indices = [0, 2, 4]
selected_elements = arr_1d[indices]
print("Selected elements:", selected_elements)
Selected elements: [1 3 5]
Transposing an array means exchanging its rows and columns. In NumPy, you can transpose an
array using the T attribute or the transpose() function.
# Create a 2D array
arr_2d = np.array([[1, 2, 3],
[4, 5, 6]])
Transposed array:
[[1 4]
[2 5]
[3 6]]
2. Swapping Axes:
Swapping axes means rearranging the dimensions of an array. You can swap axes using the
swapaxes() function.
# Create a 2D array
arr_2d = np.array([[1, 2, 3],
[4, 5, 6]])
# Swap axes
swapped_arr = arr_2d.swapaxes(0,1)
print("Swapped array:")
print(swapped_arr)
Swapped array:
[[1 4]
[2 5]
[3 6]]
[[ 2 14]
[ 6 18]
[10 22]]
[[ 3 15]
[ 7 19]
[11 23]]
[[ 4 16]
[ 8 20]
[12 24]]]
NumPy provides various functions for generating pseudo-random numbers. These functions are
located in the numpy.random module. You can generate random numbers from different
distributions, such as uniform, normal, binomial, etc.
# Generate a 2D array of shape (3, 3) with random numbers from a normal distribution
random_normal_2d = np.random.normal(size=(3, 3))
print("Random numbers from normal distribution (2D):")
print(random_normal_2d)
keyboard_arrow_down Masking
Masking in NumPy involves using boolean arrays (masks) to filter or select elements from arrays
based on certain conditions. This is particularly useful for selecting elements that satisfy specific
criteria.
1. Masking in 1D Array:
# Create a 1D array
arr_1d = np.array([1, 2, 3, 4, 5])
Original 1D array: [1 2 3 4 5]
Boolean mask: [False False True True True]
Selected elements using mask: [3 4 5]
2. Masking in 2D Array:
# Create a 2D array
arr_2d = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print("Original 2D array:")
print(arr_2d)
print("Boolean mask:")
print(mask_2d)
print("Selected elements using mask:")
print(result_2d)
Original 2D array:
[[1 2 3]
[4 5 6]
[7 8 9]]
Boolean mask:
[[False False False]
[False False True]
[ True True True]]
Selected elements using mask:
[6 7 8 9]
Matrix multiplication is a fundamental operation in linear algebra, where you multiply two matrices
to obtain a new matrix. In NumPy, you can perform matrix multiplication using the np.matmul()
function.
# Define matrices
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
Matrix Multiplication:
[[19 22]
[43 50]]
2. Reshaping ( np.reshape() ):
Reshaping an array means changing the shape of the array without changing its data. It's useful for
converting arrays between different dimensions or rearranging their layout.
# Reshaping an array
arr = np.arange(1, 10) # 1D array from 1 to 9
print(arr)
reshaped_arr = arr.reshape((3, 3)) # Reshape to a 3x3 matrix
print("Reshaped array:")
print(reshaped_arr)
[1 2 3 4 5 6 7 8 9]
Reshaped array:
[[1 2 3]
[4 5 6]
[7 8 9]]
3. Transpose ( np.transpose() ):
Transposing a matrix means flipping its rows with its columns. In NumPy, you can obtain the
transpose of a matrix using the np.transpose() function or the .T attribute.
# Transposing a matrix
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
transposed_matrix = np.transpose(matrix)
print("Transposed matrix:")
print(transposed_matrix)
Transposed matrix:
[[1 4]
[2 5]
[3 6]]
4. Aggregate Functions:
Aggregate functions in NumPy are functions that operate on arrays and return a single value,
summarizing the data in some way. Common aggregate functions include np.sum() , np.max() ,
np.min() , np.mean() , etc.
# Aggregate functions
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
# Element-wise addition
result_add = np.add(arr, 2) # Add 2 to each element
print("Addition:", result_add)
# Element-wise multiplication
result_mul = np.multiply(arr, 3) # Multiply each element by 3
print("Multiplication:", result_mul)
Addition: [3 4 5 6 7]
Multiplication: [ 3 6 9 12 15]
2. Trigonometric Functions:
# Trigonometric functions
angles = np.array([0, np.pi/4, np.pi/2, 3*np.pi/4, np.pi])
# Sine
result_sin = np.sin(angles)
print("Sine:", result_sin)
# Cosine
result_cos = np.cos(angles)
print("Cosine:", result_cos)
# Exponential
result_exp = np.exp(arr)
print("Exponential:", result_exp)
# Natural logarithm
result_log = np.log(arr)
print("Natural Logarithm:", result_log)
4. Statistical Functions:
# Statistical functions
arr = np.array([1, 2, 3, 4, 5])
# Mean
result_mean = np.mean(arr)
print("Mean:", result_mean)
# Standard deviation
result_std = np.std(arr)
print("Standard Deviation:", result_std)
Mean: 3.0
Standard Deviation: 1.4142135623730951
5. Comparison Functions:
# Comparison functions
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([2, 3, 3, 4, 4])
# Greater than
result_gt = np.greater(arr1, arr2)
print("Greater Than:", result_gt)
6. Broadcasting:
Ufuncs also support broadcasting, which means they can operate on arrays of different shapes.
NumPy automatically broadcasts arrays to perform element-wise operations.
2. resize: The resize method changes the shape and size of an array in-place. This method can
alter the original array and fill in with repeated copies of a if the new array is larger than the original.
Resized array:
[[0 1 2 3 4 5]
[6 7 8 9 0 0]]
3. ravel: The ravel method returns a flattened one-dimensional array. It's a convenient way to
convert any multi-dimensional array into a flat 1D array.
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
Flattened array: [ 0 1 2 3 4 5 6 7 8 9 10 11]
4. flatten: Similar to ravel, but flatten returns a copy instead of a view of the original data, thus not
affecting the original array.
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
Flattened array copy: [ 0 1 2 3 4 5 6 7 8 9 10 11]
# Creating a 2D array
a = np.array([[1, 2], [3, 4]])
5. squeeze: The squeeze method is used to remove axes of length one from an array.
[[1]
[2]
[3]
[4]]
Expanded array shape: (4, 1)
x = np.arange(9)
print("Original array:", x)
Original array: [0 1 2 3 4 5 6 7 8]
Split array: [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
2. np.array_split: Similar to np.split, but allows for splitting into unequal subarrays.
Array split into unequal parts: [array([0, 1, 2]), array([3, 4]), array([5, 6]),
3. np.hsplit and np.vsplit: These are specific cases of split for horizontal and vertical splitting
respectively, useful for 2D arrays (matrices).
# Vertical split
y_vsplit = np.vsplit(y, 2)
print("Vertically split:", y_vsplit)
Original 2D array:
[[1 2 3]
[4 5 6]]
Horizontally split: [array([[1],
[4]]), array([[2],
[5]]), array([[3],
[6]])]
Vertically split: [array([[1, 2, 3]]), array([[4, 5, 6]])]
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
Concatenated array: [1 2 3 4 5 6]
5. np.hstack and np.vstack: These are specific cases of concatenate for horizontal and vertical
stacking respectively.
# Horizontal stack
h_stacked = np.hstack((a, b))
print("Horizontally stacked:", h_stacked)
# Vertical stack
v_stacked = np.vstack((a, b))
print("Vertically stacked:\n", v_stacked)
Horizontally stacked: [1 2 3 4 5 6]
Vertically stacked:
[[1 2 3]
[4 5 6]]
Appended array: [1 2 3 7 8]