Okay, let's put the concepts we've discussed into practice. This section provides hands-on examples to solidify your understanding of creating and manipulating NumPy arrays, which are fundamental for implementing linear algebra operations efficiently in Python. We'll use the common convention of importing NumPy as np
.
import numpy as np
If you haven't installed NumPy yet, refer back to the "Setting Up Your Python Environment" section in Chapter 1.
First, let's revisit creating arrays. The most straightforward way is often from existing Python lists or tuples using np.array()
.
From Python Lists:
# Create a 1-dimensional array (vector)
list_a = [1, 5, 2, 7]
vector_a = np.array(list_a)
print("Vector from list:")
print(vector_a)
print("Data type:", vector_a.dtype) # Check the inferred data type
# Create a 2-dimensional array (matrix)
list_b = [[1, 2, 3], [4, 5, 6]]
matrix_b = np.array(list_b)
print("\nMatrix from list of lists:")
print(matrix_b)
print("Data type:", matrix_b.dtype)
Notice how NumPy automatically infers the data type (like int64
or float64
). You can also explicitly specify the data type using the dtype
argument:
# Create a float array
matrix_c = np.array([[1, 2], [3, 4]], dtype=np.float64)
print("\nMatrix with specified float type:")
print(matrix_c)
print("Data type:", matrix_c.dtype)
Using NumPy Functions:
NumPy provides functions to create arrays with specific patterns, which is often more efficient than creating Python lists first.
np.zeros()
: Creates an array filled with zeros.np.ones()
: Creates an array filled with ones.np.arange()
: Creates an array with a range of numbers (similar to Python's range
).np.linspace()
: Creates an array with evenly spaced numbers over a specified interval.# Create a 3x4 matrix of zeros
zeros_matrix = np.zeros((3, 4)) # Pass shape as a tuple
print("\n3x4 Matrix of zeros:")
print(zeros_matrix)
# Create a 1D array of ones
ones_vector = np.ones(5)
print("\nVector of ones:")
print(ones_vector)
# Create an array from 0 up to (but not including) 10
range_array = np.arange(10)
print("\nArray using arange(10):")
print(range_array)
# Create an array from 2 to 10, step 2
range_step_array = np.arange(2, 11, 2) # Start, Stop (exclusive), Step
print("\nArray using arange(2, 11, 2):")
print(range_step_array)
# Create an array with 5 evenly spaced points between 0 and 1
linspace_array = np.linspace(0, 1, 5) # Start, Stop (inclusive), Number of points
print("\nArray using linspace(0, 1, 5):")
print(linspace_array)
Once you have an array, you need to access its elements. NumPy uses zero-based indexing, similar to Python lists.
1D Arrays:
my_vector = np.arange(5, 11) # Creates [5, 6, 7, 8, 9, 10]
print("\nOriginal vector:", my_vector)
# Access the first element (index 0)
first_element = my_vector[0]
print("First element:", first_element)
# Access the last element (index -1)
last_element = my_vector[-1]
print("Last element:", last_element)
# Get a slice: elements from index 1 up to (not including) index 4
slice_1_to_3 = my_vector[1:4]
print("Slice [1:4]:", slice_1_to_3)
# Get a slice from the beginning up to index 3
slice_start_to_2 = my_vector[:3]
print("Slice [:3]:", slice_start_to_2)
# Get a slice from index 3 to the end
slice_3_to_end = my_vector[3:]
print("Slice [3:]:", slice_3_to_end)
# Modify an element
my_vector[2] = 99
print("Modified vector:", my_vector)
# Modify a slice
my_vector[0:2] = [100, 101] # Assign a list or another NumPy array
print("Vector after slice modification:", my_vector)
2D Arrays (Matrices):
For 2D arrays, you use comma-separated indices or slices: [row_index, column_index]
or [row_slice, column_slice]
.
my_matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("\nOriginal matrix:")
print(my_matrix)
# Access element at row 1, column 2 (value 6)
element_1_2 = my_matrix[1, 2]
print("Element at [1, 2]:", element_1_2)
# Access the entire second row (index 1)
row_1 = my_matrix[1, :] # Use ':' to select all columns
print("Second row:", row_1)
# Alternative syntax for selecting a full row
row_1_alt = my_matrix[1]
print("Second row (alternative):", row_1_alt)
# Access the entire third column (index 2)
col_2 = my_matrix[:, 2] # Use ':' to select all rows
print("Third column:", col_2)
# Get a submatrix: rows 0 and 1, columns 1 and 2
sub_matrix = my_matrix[0:2, 1:3]
print("\nSubmatrix [0:2, 1:3]:")
print(sub_matrix)
# Modify an element
my_matrix[0, 0] = -1
print("\nMatrix after modifying element [0, 0]:")
print(my_matrix)
# Modify a column
my_matrix[:, 0] = [10, 20, 30] # Assign a list or array of the correct size
print("\nMatrix after modifying first column:")
print(my_matrix)
NumPy allows you to perform element-wise arithmetic operations directly on arrays, provided their shapes are compatible (or broadcastable, a concept we'll touch upon later).
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
scalar = 2
print("\nArray 1:", arr1)
print("Array 2:", arr2)
print("Scalar:", scalar)
# Element-wise addition
addition = arr1 + arr2
print("arr1 + arr2:", addition)
# Element-wise subtraction
subtraction = arr1 - arr2
print("arr1 - arr2:", subtraction)
# Element-wise multiplication
multiplication = arr1 * arr2
print("arr1 * arr2:", multiplication)
# Element-wise division
division = arr1 / arr2
print("arr1 / arr2:", division)
# Scalar multiplication
scalar_mult = arr1 * scalar
print("arr1 * scalar:", scalar_mult)
# Scalar addition (adds scalar to every element)
scalar_add = arr1 + scalar
print("arr1 + scalar:", scalar_add)
# Operations work similarly for matrices
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
print("\nMatrix 1:")
print(matrix1)
print("Matrix 2:")
print(matrix2)
matrix_sum = matrix1 + matrix2
print("Matrix sum:")
print(matrix_sum)
matrix_prod = matrix1 * matrix2 # Note: This is ELEMENT-WISE multiplication
print("Matrix element-wise product:")
print(matrix_prod)
Important Note: The *
operator performs element-wise multiplication for NumPy arrays. This is different from standard matrix multiplication (the dot product), which we will cover in detail in Chapter 5.
Knowing the properties of your arrays is essential. NumPy arrays have several useful attributes:
ndim
: Number of dimensions.shape
: A tuple representing the size of the array in each dimension (rows, columns, etc.).size
: Total number of elements in the array.dtype
: Data type of the elements.matrix = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print("\nSample Matrix:")
print(matrix)
print("Number of dimensions (ndim):", matrix.ndim)
print("Shape (shape):", matrix.shape) # (rows, columns)
print("Total size (size):", matrix.size)
print("Data type (dtype):", matrix.dtype)
You can change the shape of an array without changing its data using the reshape()
method. The new shape must have the same total number of elements (size
).
vector = np.arange(12) # Array from 0 to 11
print("\nOriginal vector (size 12):", vector)
# Reshape into a 3x4 matrix (3*4 = 12 elements)
matrix_3x4 = vector.reshape(3, 4)
print("\nReshaped to 3x4 matrix:")
print(matrix_3x4)
print("New shape:", matrix_3x4.shape)
# Reshape into a 4x3 matrix (4*3 = 12 elements)
matrix_4x3 = vector.reshape(4, 3)
print("\nReshaped to 4x3 matrix:")
print(matrix_4x3)
print("New shape:", matrix_4x3.shape)
# Try to reshape into an incompatible shape (e.g., 3x5 = 15 elements)
try:
vector.reshape(3, 5)
except ValueError as e:
print("\nReshape error (expected):", e)
# Using -1 in reshape: NumPy calculates the dimension automatically
# Reshape into a matrix with 2 rows (NumPy figures out columns)
matrix_2x_auto = vector.reshape(2, -1) # -1 means "figure it out"
print("\nReshaped to 2 rows (auto columns):")
print(matrix_2x_auto)
print("New shape:", matrix_2x_auto.shape) # Will be (2, 6)
# Reshape into a matrix with 3 columns (NumPy figures out rows)
matrix_auto_x3 = vector.reshape(-1, 3)
print("\nReshaped to 3 columns (auto rows):")
print(matrix_auto_x3)
print("New shape:", matrix_auto_x3.shape) # Will be (4, 3)
Reshaping is frequently used in machine learning to prepare data for different algorithms or layers in a neural network, which often expect inputs of specific dimensions.
These examples cover the fundamental mechanics of creating, accessing, modifying, and inspecting NumPy arrays. As you progress through the course, you'll see these operations applied repeatedly in the context of vectors and matrices for linear algebra. Spend some time experimenting with these functions and operations to build familiarity. They are the building blocks for the more complex computations ahead.
© 2025 ApX Machine Learning