What is Numerical Python
NumPy is a Python library that forms the foundation of scientific and numerical computations in Python. NumPy stands for Numerical Python.
Since machine learning involves transforming data into numbers and finding patterns, NumPy is often a critical component.
Why NumPy
Numerical computations can be done using pure Python. At first, Python might seem fast, but as the data size grows, significant slowdowns become noticeable.
To address these performance challenges, NumPy provides efficient array operations that work much faster and more effectively with large datasets.
Import the library
# importing the NumPy library & checking its version
import numpy as np
print(f"NumPy version: {np.__version__}")
Know available Data Types & Their Attributes
Note: In NumPy, the core data type is the ndarray. Regardless of their apparent differences, all arrays fall under the ndarray type. This ensures that operations performed on one array type are compatible with others.
ndarray – Data Type
# A one-dimensional array, aka 'vector' a1 = np.array([1, 2, 3]) a1
array([1, 2, 3])
# Two-Dimensional Array, aka 'Matrix'
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
a2
array([[1.1, 2.2, 3.3],
[4.4, 5.5, 6.6]])
# Three-Dimensional Array, Also Known as a 'Matrix'
a3 = np.array(
[
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
[
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]
]
]
)
a3
array([[[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]])
ndarray – Attributes
# Display the Shape of the Array a1.shape
(3,)
# Display the Number of Dimensions of the Array a1.ndim
1
# Display the Data Type in the Array a1.dtype
dtype('int64')
# Display the Size of the Array - Number of Elements a1.size
3
# The 'type()' Function, Built into Python, Provides the Type of a Variable/Object type(a1)
numpy.ndarray
# All the above in a concise form a2.shape, a2.ndim, a2.dtype, a2.size, type(a2)
((2, 3), 2, dtype('float64'), 6, numpy.ndarray)
# All the above in a concise form a3.shape, a3.ndim, a3.dtype, a3.size, type(a3)
((2, 3, 3), 3, dtype('int64'), 18, numpy.ndarray)
“Types” of arrays
Arrays with different dimensions have a different name and meaning.
- Array – a list of numbers, can be multidimensional.
- Scalar – a single number (e.g.,
7). - Vector – a one-dimensional list of numbers (e.g.,
np.array([1, 2, 3])). - Matrix – (usually) a multidimensional list of numbers (e.g.,
np.array([[1, 2, 3], [4, 5, 6]])).
Note: The above description is in the context of ndarray. Remember that arrays can store different types of elements, not just numbers.
Creating pandas DataFrame using NumPy arrays
# Creating a 'DataFrame' with 'pandas' Based on an array from 'NumPy'
import numpy as np
import pandas as pd
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
df2_from_a2 = pd.DataFrame(a2)
df2_from_a2
| 0 | 1 | 2 | |
|---|---|---|---|
| 0 | 1.1 | 2.2 | 3.3 |
| 1 | 4.4 | 5.5 | 6.6 |
Creating arrays
“Manual” creation of arrays using NumPy functions.
# Creating a simple array simple_array = np.array([1, 2, 3]) # Display the array + info about the data type (simple_array, simple_array.dtype)
(array([1, 2, 3]), dtype('int64'))
# Creating an array filled with ones ones = np.ones((3, 2)) # Display the array + info about the data type (ones, ones.dtype)
(array([[1., 1.],
[1., 1.],
[1., 1.]]),
dtype('float64'))
# Changing the data type - 'astype()' function ones.astype(int) # Notice in the below output there is no (dot) . sign after digit # (float) 1. # (int) 1
array([[1, 1],
[1, 1],
[1, 1]])
# Creating an array filled with zeros zeros = np.zeros((3, 2)) # Display the array + info about the data type (zeros, zeros.dtype)
(array([[0., 0.],
[0., 0.],
[0., 0.]]),
dtype('float64'))
# Creating an array within a specified range in_range_array = np.arange(0, 10, 2) in_range_array
array([0, 2, 4, 6, 8])
# Creating an array with random integers np.random.randint(10, size=(5, 3))
array([[6, 8, 3],
[5, 9, 4],
[2, 6, 9],
[8, 4, 4],
[1, 0, 2]])
# Creating an array with random floats (between 0 and 1) np.random.rand(5, 3)
array([[0.3739472 , 0.10567113, 0.51323787],
[0.03793473, 0.66479983, 0.78655543],
[0.11558726, 0.08336928, 0.02401844],
[0.82549147, 0.84921565, 0.45672526],
[0.77683918, 0.7307675 , 0.42186085]])
# Using np.random.seed() allows you to set this seed, ensuring that the sequence of generated random numbers is repeatable. np.random.seed(0) # Creating 'pandas.DataFrame' filled with random integers df = pd.DataFrame(np.random.randint(10, size=(5, 3))) # Display the DataFrame df
| 0 | 1 | 2 | |
|---|---|---|---|
| 0 | 5 | 0 | 3 |
| 1 | 3 | 7 | 9 |
| 2 | 3 | 5 | 2 |
| 3 | 4 | 7 | 6 |
| 4 | 8 | 8 | 1 |
Manipulating arrays
With the NumPy library, arrays can be manipulated and compared through techniques such as performing arithmetic operations, leveraging broadcasting, applying aggregation functions, implementing transformations, swapping elements, calculating dot products, and utilizing comparison operators.
Arithmetic operations
# Preparing arrays for arithmetic operations
a1 = np.array([1, 2, 3])
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
ones = np.ones(3)
# Adding two arrays a1 + ones
array([2., 3., 4.])
# Subtracting two arrays a1 - ones
array([0., 1., 2.])
# Multiplying two arrays a1 * a2
array([[ 1.1, 4.4, 9.9],
[ 4.4, 11. , 19.8]])
Broadcasting
NumPy broadcasting allows arrays of different shapes to be automatically aligned during arithmetic operations, enabling efficient computations without explicitly replicating data.
In NumPy, broadcasting aligns arrays by comparing their shapes from right to left. Dimensions are compatible if they are equal, one of them is 1, or one array has fewer dimensions (implicitly padded with 1s).
Broadcasting is a powerful tool that enables fast and efficient calculations without explicit loops. It saves memory by avoiding the creation of unnecessary copies of data.
# Adding a scalar value to an array arr = np.array([1, 2, 3]) # A scalar value is broadcasted to match the shape of the array result = arr + 10 result
array([11, 12, 13])
# Adding two arrays with different shapes
first_array = np.array([
[1, 2, 3],
[4, 5, 6]
])
second_array = np.array([10, 20, 30])
print(f"Shape of the first array: {first_array.shape}, Shape of the second array: {second_array.shape}")
Shape of the first array: (2, 3), Shape of the second array: (3,)
# The 'second_array' is broadcasted to each row of 'first_array' result = first_array + second_array result
array([[11, 22, 33],
[14, 25, 36]])
# Broadcasting with higher dimensions
# Adding two arrays with different shapes
first_array = np.array([1, 2, 3])
second_array = np.array([[10], [20]])
print(f"Shape of the first array: {first_array.shape}, Shape of the second array: {second_array.shape}")
Shape of the first array: (3,), Shape of the second array: (2, 1)
# Broadcasting with higher dimensions # Adding two arrays with different shapes result = first_array + second_array result
array([[11, 12, 13],
[21, 22, 23]])
In this example, first_array with the shape (3,) is broadcasted along the columns, while second_array with the shape (2, 1) is broadcasted along the rows, resulting in the shape of (2, 3).
Aggregation
Array aggregation in NumPy involves summarizing data by applying functions like sum, mean, min, max, and others across an entire array or along specific axes.
# Preparing data for aggregation operations
a1 = np.array([1, 2, 3])
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
a3 = np.array(
[
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
[
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]
]
]
)
np.sum(a1)
6
Let’s see whether operations on arrays in the NumPy are faster than those performed in pure Python.
# Preparing data very_large_array = np.random.random(100000) very_large_array.size, type(very_large_array)
(100000, numpy.ndarray)
# 'sum()' function from Python %timeit sum(very_large_array) # 'sum()' function from the NumPy library %timeit np.sum(very_large_array) # NumPy np.sum()
11.2 ms ± 643 μs per loop (mean ± std. dev. of 7 runs, 100 loops each) 59.3 μs ± 3.23 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
The timing results indicate a significant performance difference between operations in pure Python and NumPy. Pure Python operations take approximately 11.2 ms per loop, while NumPy operations take only 59.3 µs per loop. This demonstrates that NumPy is roughly 188 times faster than pure Python for this specific operation, highlighting its efficiency for numerical computations.
# Function returning the mean np.mean(a2)
3.85
# Function returning the minimum value np.min(a3)
1
# Function returning the maximum value np.max(a3)
18
# Function returning the standard deviation np.std(a2)
1.8786076404259262
# Function returning the variance np.var(a2)
3.5291666666666663
# The standard deviation is the square root of the variance np.sqrt(np.var(a2))
1.8786076404259262
Mean: In the context of machine learning, the mean (or average) is a measure of central tendency. It represents the average value of a dataset, calculated by summing all values and dividing by the number of elements. It is often used to understand the central point of a dataset.

Variance: Variance measures the spread of a dataset. It quantifies how far each data point is from the mean. A high variance indicates that data points are spread out, while a low variance means they are close to the mean.

Standard Deviation: The standard deviation is the square root of the variance. It also measures the spread of the data but is expressed in the same units as the data, making it easier to interpret. It is commonly used in machine learning to understand how much the data deviates from the mean.

Reshaping
# Preparing data for aggregation operations
a1 = np.array([1, 2, 3])
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
a3 = np.array(
[
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
[
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]
]
]
)
# Display info about the shape of the arrays 'a2' and 'a3' (a2.shape, a3.shape)
((2, 3), (2, 3, 3))
When broadcasting does not work we need to reshape the arrays. For this (a2 + a3) summation, we will encounter an error: ValueError: operands could not be broadcast together with shapes (2,3) (2,3,3)
a2r = a2.reshape(2, 3, 1) a2r
array([[[1.1],
[2.2],
[3.3]],
[[4.4],
[5.5],
[6.6]]])
a2r + a3
array([[[ 2.1, 3.1, 4.1],
[ 6.2, 7.2, 8.2],
[10.3, 11.3, 12.3]],
[[14.4, 15.4, 16.4],
[18.5, 19.5, 20.5],
[22.6, 23.6, 24.6]]])
Transpose
In NumPy, array transposition rearranges the dimensions of an array. It can be achieved using the numpy.transpose() function or the .T attribute, both providing the same result by flipping rows and columns for 2D arrays or reordering axes for higher-dimensional arrays.
# Data for the example of swapping rows with columns
# Creating a 2D array (matrix)
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
# Using numpy.transpose() to transpose the matrix
transposed_matrix = np.transpose(matrix)
print(f"\nOriginal matrix: \n{matrix}")
print(f"\nTransposed using numpy.transpose(): \n{transposed_matrix}")
Original matrix: [[1 2 3] [4 5 6]] Transposed using numpy.transpose(): [[1 4] [2 5] [3 6]]
# Using the .T attribute to transpose the matrix
transposed_matrix_T = matrix.T
print(f"\nOriginal matrix: \n{matrix}")
print(f"\nTransposed using the .T attribute: \n{transposed_matrix_T}")
Original matrix: [[1 2 3] [4 5 6]] Transposed using the .T attribute: [[1 4] [2 5] [3 6]]
Applications in Machine Learning: In machine learning, matrix transposition is frequently used in operations such as:
- Preparing data for linear algebra operations (e.g., dot products).
- Matching dimensions to meet algorithm input requirements.
- Transforming datasets in operations like matrix multiplication (where inner dimensions must align).
Dot Product
In machine learning, mathematical operations on vectors and matrices are fundamental for tasks like linear transformations, data manipulation, and implementing algorithms such as linear regression or neural networks.
The dot product of two vectors is a scalar value obtained by multiplying their corresponding components and summing the results.
When dealing with matrices, the dot product operation extends to matrix multiplication. If A is an m × n matrix and B is an n × p matrix, their dot product (matrix multiplication) C is an m × p matrix.
# The dot product of two vectors np.dot([1, 2, 3], [4, 5, 6]) # Result: 32
# Matrix-vector multiplication
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
vector = np.array([7, 8, 9])
# Calculating the dot product
result = np.dot(matrix, vector)
print(f"Matrix:\n{matrix}")
print(f"Vector: {vector}")
print(f"Result (Matrix * Vector): {result}")
Matrix: [[1 2 3] [4 5 6]] Vector: [7 8 9] Result (Matrix * Vector): [ 50 122]
# Matrix-matrix multiplication np.dot([[1, 2], [3, 4]], [[5, 6], [7, 8]])
array([[19, 22],
[43, 50]])
Comparing arrays
# Preparing data for aggregation operations
a1 = np.array([1, 2, 3])
a2 = np.array(
[
[1.1, 2.2, 3.3], [4.4, 5.5, 6.6]
]
)
a3 = np.array(
[
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
],
[
[10, 11, 12],
[13, 14, 15],
[16, 17, 18]
]
]
)
a1 > a2
array([[False, False, False],
[False, False, False]])
a1 >= a2
array([[ True, True, False],
[False, False, False]])
a1 > 5
array([False, False, False])
a1 == a1
array([ True, True, True])
a1 == a2
array([[ True, True, False],
[False, False, False]])
Sorting arrays
# Preparing data for sorting operations a1 = np.array([1, 2, 3]) # Array with random values random_array = np.random.randint(10, size=(5, 3)) # Display random array values random_array
array([[5, 0, 8],
[1, 4, 7],
[5, 5, 6],
[2, 6, 2],
[9, 6, 1]])
np.sort(random_array)
array([[0, 5, 8],
[1, 4, 7],
[5, 5, 6],
[2, 2, 6],
[1, 6, 9]])
np.argsort(random_array)
array([[1, 0, 2],
[0, 1, 2],
[0, 1, 2],
[0, 2, 1],
[2, 1, 0]])
np.argsort(a1)
array([[1, 0, 2],
[0, 1, 2],
[0, 1, 2],
[0, 2, 1],
[2, 1, 0]])
np.argmin(a1)
0
# Verticaly np.argmax(random_array, axis=1)
array([2, 2, 2, 1, 0])
# Horizontaly np.argmax(random_array, axis=0)
array([4, 3, 0])
NOTE: In this article, I’m just barely scratching the surface. This topic needs more reading and research on your own. I’m still at the beginning of my learning process of AI & ML!




Leave a Reply