Enable Dark Mode!
By: Arwa VV

Python NumPy Tutorial – 2024

Technical

NumPy, which stands for Numerical Python, is an essential Python library that supports matrices, arrays and various mathematical operations for effectively manipulating these data structures.
In this blog, we’ll discuss NumPy and its key features.
In Python, lists can be used in place of arrays, although they process data slowly. We use NumPy in place of Python lists because it is faster than Python lists. With NumPy, an array object can be created up to 50 times faster than with conventional Python lists. NumPy arrays are relatively efficient to access and modify because, unlike lists, they are kept in memory continuously. This is the reason why NumPy is faster than Python lists. The array object in NumPy is called ndarray.
To install NumPy, run the below command:
`pip install numpy`
We can create a NumPy array as following:
`import numpyarr = numpy.array([1, 2, 3, 4, 5])print(arr)    # Output : [1 2 3 4 5] 		`
NumPy is usually imported under the np alias.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])print(arr)    # Output : [1 2 3 4 5]`
To the type of above array:
`print(type(arr))`
Output : <class ‘numpy.ndarray’>
We can pass a list, tuple or any array-like object into the array() method to create an ndarray.

Dimensions in Arrays:

In NumPy, arrays can have multiple dimensions, allowing you to represent data in a more structured way compared to Python's standard lists.
0-D Arrays:
0-D arrays, or Scalars, are the elements in an array. Each value in an array is a 0-D array.
1-D Arrays:
A one-dimensional array is similar to a Python list. It consists of elements arranged in a single line. It can also be defined as an array that has 0-D arrays as its elements.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])print(arr)    # Output: [1, 2, 3, 4, 5]`
2-D Arrays:
A two-dimensional array is like a matrix, organized as rows and
columns. It can also be defined as an array that has 1-D arrays as its elements.
`import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])print(arr)    # Output: [[1, 2, 3], [4, 5, 6]]`
3-D arrays:
An array that has 2-D arrays (matrices) as its elements is called 3-D array. NumPy allows arrays with more than two dimensions. These can represent data in multiple dimensions, such as 3D arrays or higher.
`import numpy as nparr = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])print(arr)`
Output:      [[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]]

ndim:

We can check the dimension of NumPy arrays using the attribute ndim. It will return
an integer that indicates how many dimensions the array has.
`import numpy as npa = np.array(20)b = np.array([1, 2, 3, 4])c = np.array([[1, 2, 3], [4, 5, 6]])print(a.ndim)        # Output: 0print(b.ndim)        # Output: 1print(c.ndim)        # Output: 2`

ndmin:

To create an array with your desired specific number of dimension, you can use the ndmin argument as follows:
`import numpy as nparr = np.array([1, 2, 3, 4], ndmin=4)print(arr)     # Output: [[[[1 2 3 4]]]]print('dimensions :', arr.ndim)     # Output: 4`
Array Indexing:
You can access an array element by referring to its index number
`import numpy as nparr = np.array([1, 2, 3, 4])print(arr[0], arr[1], arr[2])     # Output: 1 2 3`
To access 2-D array element:
`import numpy as nparr = np.array([[1,2,3,4,5], [6,7,8,9,10]])print('2nd element on 1st row: ', arr[0, 1])print('5th element on 2nd row: ', arr[1, 4])Output:2nd element on 1st row:  25th element on 2nd row:  10`
To access 3-D array element:
`import numpy as nparr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])print(arr[0, 1, 2])Output: 6`
In this case, [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]] is a 3D array with two 2D arrays as its elements ( [[1, 2, 3], [4, 5, 6]] and [[7, 8, 9], [10, 11, 12]] ).
So, first as we selected index 0, we have the element [[1, 2, 3], [4, 5, 6]]
Next, we selected index 1 in [[1, 2, 3], [4, 5, 6]], so we have the element [4, 5, 6].
In [4, 5, 6], we selected index 2, we have element 6 which is the final output.
To access an array from the end, we can use negative indexing
`import numpy as nparr1 =  np.array([1,2,3,4,5])print('Last element in arr1: ', arr1[-1])arr2 = np.array([[1,2,3,4,5], [6,7,8,9,10]])print('Last element from 2nd dim in arr2: ', arr2[1, -1])Output:Last element in arr1:  5Last element from 2nd dim in arr2:  10`

Array Slicing:

In NumPy, extracting a section of an array by defining a range of indices along each dimension is referred to as array slicing.
In place of an index, we pass a slice as [start : end].
We can also define the step, like this: [start:end:step].
If we don't give ‘start’ it’s considered 0.
If we don't give ‘end’ it’s considered the length of the array in that dimension.
If we don't pass step it's considered 1.
The result includes the start index, but excludes the end index.
`import numpy as nparr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])print(arr[2:6])      # Output: [3 4 5 6]`
Here the start index is 2, and the end index is 6. As we have not provided a step, step would be 1. So elements from index 2 to index 6  (not included) will be taken.
`print(arr[2:8:2])    # Output: [3 5 7]`
In this case, the start index is 2, the end index is 8 and the step is 2, meaning every second element within the specified range will be included.
`print(arr[4:])      # Output: [ 5  6  7  8  9 10]`
In this case, elements from index 4 to the end of the array are sliced.
`print(arr[:4])      # Output: [1 3 5 7]`
In this case, elements from the beginning to index 4 (not included) are sliced.
`import numpy as nparr = np.array([1, 2, 3, 4, 5, 6, 7])print(arr[::2])     # Output: [1 3 5 7]`
Slicing 2D array:
`import numpy as nparr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])print(arr[0, 1:4])   # Output: [2 3 4]`
Here, as we selected 0, we have the element [1, 2, 3, 4, 5]. From this, elements from index 1 to index 4  (not included) will be taken.
`import numpy as nparr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])print(arr[0:2, 1:4])`
Here, from both elements, slice index 1 to index 4 (not included), this will return a 2-D array.
Copy vs View:
In NumPy, "copy" and "view" affect how data is managed and modified, particularly when dealing with large datasets. The distinction between a copy and a view lies in how NumPy handles memory allocation and references to the original data.
Copy creates a new array that is completely independent of the original array. Modifications to the copied array do not affect the original data.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])arr_copy = arr.copy()arr_copy[0] = 10print(arr_copy)  # Output: [10, 2, 3, 4, 5]print(arr)       # Output: [1, 2, 3, 4, 5]`
View creates a new array object that references the same data as the original array. Modifications to the view affect the original data as well.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])arr_view = arr.view()arr_view[0] = 10print(arr_view)  # Output: [10, 2, 3, 4, 5]print(arr)       # Output: [10, 2, 3, 4, 5]`
You can check whether an array is a copy or a view using the base attribute. If an array is a view, its base attribute will refer to the original array.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])arr_view = arr.view()arr_copy = arr.copy()print(arr_view.base)  # Output: [1 2 3 4 5]print(arr_copy.base)  # Output: None`

Shape:

In NumPy,  the shape of an array refers to the array’s dimensions or structure, indicating the number of elements along each axis. The shape of a NumPy array is described by a tuple of integers, where each integer represents the size of a particular dimension.
`import numpy as nparr_2d = np.array([[1, 2, 3], [4, 5, 6]])print(arr_2d.shape)  # Output: (2, 3) - 2 rows, 3 columns`

Reshape:

Reshaping arrays in NumPy refers to changing the dimensions or structure of an array while maintaining the total number of elements. This operation allows you to alter the shape of the array without changing the data it contains.
Reshape from 1D to 2D:
`import numpy as nparr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])newarr = arr.reshape(4, 3)print(newarr)#Output:[[ 1  2  3] [ 4  5  6] [ 7  8  9] [10 11 12]]`
The outermost dimension will have 4 arrays, each with 3 elements
Reshape From 1-D to 3-D:
`import numpy as nparr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])newarr = arr.reshape(2, 3, 2)print(newarr)# Output:[[[ 1  2]  [ 3  4]  [ 5  6]] [[ 7  8]  [ 9 10]  [11 12]]]`
The outermost dimension will have 2 arrays that contain 3 arrays, each with 2 elements.

Array Iterating:

Using Loops:
For Loop:
Iterating through a NumPy array using a basic for loop is straightforward:
`import numpy as nparr = np.array([1, 2, 3, 4, 5])for element in arr:    print(element)# Output:12345`
Iterating through Multidimensional Arrays:
For multidimensional arrays, nested loops are used to access elements.
`import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])for row in arr:    for element in row:        print(element)# Output:123456`

nditer():

The nditer() function allows efficient iteration through arrays, especially for multidimensional arrays.
`import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])for element in np.nditer(arr):    print(element)# Output:123456`

Joining Arrays:

In NumPy, you can join or concatenate arrays using functions like np.concatenate(), np.vstack() (vertical stack), np.hstack() (horizontal stack), np.dstack() (depth stack), etc.
Here are examples of how to use these functions:
np.concatenate() joins a sequence of arrays along an existing axis.
`import numpy as nparray1 = np.array([[1, 2, 3], [4, 5, 6]])array2 = np.array([[7, 8, 9], [10, 11, 12]])# Concatenating along axis 0 (rows)result_concat_axis0 = np.concatenate((array1, array2), axis=0)print("Concatenated along axis 0:\n", result_concat_axis0)# Concatenating along axis 1 (columns)result_concat_axis1 = np.concatenate((array1, array2), axis=1)print("\nConcatenated along axis 1:\n", result_concat_axis1)Output:Concatenated along axis 0: [[ 1  2  3] [ 4  5  6] [ 7  8  9] [10 11 12]]Concatenated along axis 1: [[ 1  2  3  7  8  9] [ 4  5  6 10 11 12]]`
np.vstack() and np.hstack() stack arrays vertically and horizontally, respectively.
`import numpy as nparray1 = np.array([[1, 2],                   [3, 4]])array2 = np.array([[5, 6],                   [7, 8]])# Vertical stackingresult_vstack = np.vstack((array1, array2))print("Vertically stacked arrays:\n", result_vstack)# Horizontal stackingresult_hstack = np.hstack((array1, array2))print("\nHorizontally stacked arrays:\n", result_hstack)`
Output:
Vertically stacked arrays:
[[1 2]
[3 4]
[5 6]
[7 8]]
Horizontally stacked arrays:
[[1 2 5 6]
[3 4 7 8]]
np.dstack() stacks arrays along the third axis (depth).
`import numpy as nparray1 = np.array([[1, 2],                   [3, 4]])array2 = np.array([[5, 6],                   [7, 8]])`
# Depth stacking
result_dstack = np.dstack((array1, array2))
print("Depth stacked arrays:\n", result_dstack)
Output:
Depth stacked arrays:
[[[1 5]
[2 6]]
[[3 7]
[4 8]]]

Array Splitting:

In NumPy, you can split arrays into multiple smaller arrays using functions like np.split(), np.array_split(), np.vsplit() (vertical split), np.hsplit() (horizontal split), np.dsplit() (depth split), etc.
np.split() splits an array into multiple sub-arrays along a given axis.
`import numpy as nparr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])# Splitting the array into 3 equal parts along axis 0result_split = np.split(arr, 3)print(result_split)`
Output:
[array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]
Unlike np.split(), np.array_split() allows splitting arrays into unequal parts.
`import numpy as nparr = np.arange(10)result_array_split = np.array_split(arr, 4)print(result_array_split)`
Output:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7]), array([8, 9])]
np.vsplit() and np.hsplit() split arrays vertically and horizontally, respectively.
`import numpy as nparr = np.array([[1, 2, 3],                [4, 5, 6],                [7, 8, 9],                [10, 11, 12]])# Vertical splitting into 2 partsresult_vsplit = np.vsplit(arr, 2)print("Vertically split:\n", result_vsplit)# Horizontal splitting into 3 partsresult_hsplit = np.hsplit(arr, 3)print("\nHorizontally split:\n", result_hsplit)`
Output:
Vertically split:
[array([[1, 2, 3],[4, 5, 6]]),
array([[ 7,  8,  9],[10, 11, 12]])]
Horizontally split:
[array([[ 1],
[ 4],
[ 7],
[10]]),
array([[ 2],
[ 5],
[ 8],
[11]]),
array([[ 3],
[ 6],
[ 9],
[12]])]
np.dsplit() splits arrays along the third axis (depth).
`import numpy as nparr = np.array([[[1, 2],                 [3, 4]],                                [[5, 6],                 [7, 8]]])# Depth splittingresult_dsplit = np.dsplit(arr, 2)print("Depth split:\n", result_dsplit)`
Output:
Depth split:
[array([[[1], [3]], [[5], [7]]]),
array([[[2],[4]], [[6],[8]]])]

Searching in Arrays:

In NumPy, you can perform searching operations on arrays to find specific elements or indices using functions like np.where(), np.searchsorted(), np.nonzero(), np.extract().
np.where() returns the indices of elements in an array that satisfy a given condition.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])# Find indices where elements are greater than 2indices = np.where(arr > 2)print(indices)     # Output: (array([2, 3, 4]),)`
np.searchsorted() finds the indices at which elements should be placed in order to maintain order in a sorted array.
`import numpy as nparr = np.array([1, 3, 5, 7, 9])# Find indices where 6 should be inserted to maintain sorted # orderindex = np.searchsorted(arr, 6)print(index)       # Output: 3`
np.nonzero() returns the indices of elements that are non-zero.
`import numpy as nparr = np.array([0, 2, 0, 4, 0, 6])# Find indices of non-zero elementsindices = np.nonzero(arr)print(indices)       # Output: (array([1, 3, 5]),)`
np.extract() returns elements from an array that satisfy a specified condition.
`import numpy as nparr = np.array([1, 2, 3, 4, 5])# Extract elements that are greater than 2result = np.extract(arr > 2, arr)print(result)       # Output:  [3 4 5]`

Array Sorting:

In NumPy, you can sort arrays using various functions available in the library. Here are some commonly used methods for sorting NumPy arrays:
np.sort() returns a sorted copy of an array along a specified axis.
`import numpy as nparr = np.array([3, 1, 5, 2, 4])sorted_arr = np.sort(arr)print(sorted_arr)  # Output: [1 2 3 4 5]`
In case of 2D array:
`import numpy as nparr = np.array([[3, 2, 4], [5, 0, 1]])print(np.sort(arr))`
Output:
[[2 3 4]
[0 1 5]]
np.argsort() returns the indices that would sort an array.
`import numpy as nparr = np.array([3, 1, 5, 2, 4])indices = np.argsort(arr)print(indices)  # Output: [1 3 0 4 2]`
These are some of the key features of NumPy. We will discuss the NumPy random and NumPy ufuncs in another blog.  In conclusion, NumPy stands as a powerhouse for handling numerical operations and large datasets in Python. Its efficiency in array operations, mathematical functions, and data manipulation makes it a go-to library for scientific computing, machine learning, and data analysis applications.

If you need any assistance in odoo, we are online, please chat with us.

Recent Posts

How to Dynamically Change the String of a Field Using _get_view in Odoo 17

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Kochi, India - 682030.

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,