NumPy – Numerical Data Analysis and Manipulation in Python – Introduction _ Machine Learning Maverick

NumPy – Numerical Data Analysis and Manipulation in Python – Introduction

NumPy – Numerical Data Analysis and Manipulation in Python – Introduction

ml-maverick

Share this:

NumPy – Numerical Data Analysis and Manipulation in Python – Introduction _ Machine Learning Maverick

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
012
01.12.23.3
14.45.56.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
012
0503
1379
2352
3476
4881

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

Your email address will not be published. Required fields are marked *

ml-maverick

Hi, I’m Jacek. 𝗔𝗜-𝗠𝗶𝗻𝗱𝗲𝗱 𝗚𝘂𝘆 – I work with and teach about machine learning – self-taught. I’m interested in machine learning from the technical and mathematical perspective. 𝗠𝗲𝗻𝘁𝗼𝗿, 𝗧𝗿𝗮𝗶𝗻𝗲𝗿 𝗳𝗼𝗿 𝗦𝗼𝗳𝘁𝘄𝗮𝗿𝗲 𝗗𝗲𝘃𝗲𝗹𝗼𝗽𝗲𝗿𝘀 – Helping others to change their current occupation to Junior Java Developer. I hope you will find something interesting on my blog.

RECENT POST


RECENT COMMENT