Multi-Dimensional Arrays in Python – Matrices Explained with Examples

Matrices, also known as multi-dimensional arrays, are one of the most important data structures for numerical computing in Python. At its core, a matrix is a rectangular grid of numbers arranged into rows and columns. Matrices allow you to store and manipulate data that has an inherent 2D structure, such as images, spreadsheets, or the state of a board game.

Python does not have a built-in matrix data type, but thankfully the NumPy library provides an easy-to-use and highly efficient implementation. In this article, I‘ll explain what matrices are, how to create and work with them in Python, and walk through some real-world applications. By the end, you‘ll have a solid foundation for using matrices in your own data science and programming projects.

What is a Matrix?

A matrix is a two-dimensional array of numbers with a fixed number of rows and columns. We refer to these dimensions as the shape of the matrix. Each individual element is identified by a pair of indices (i, j) where i is the row number and j is the column number. By convention, we 0-index the rows and columns, so the top-left element is (0, 0).

Here is an example of a 3×3 matrix:

[[1, 2, 3],
 [4, 5, 6], 
 [7, 8, 9]]

The first row contains the elements 1, 2, and 3. The second row contains 4, 5, and 6. And the third row contains 7, 8, and 9. To access an individual element, we use the notation A[i,j]. For example, A[1,2] = 6.

Matrices have many special properties that make them useful for mathematics and computation. The key one is that matrices can be added, subtracted, and multiplied according to certain rules. Matrix algebra provides a compact notation for representing and solving systems of linear equations, which have important applications in physics, engineering, statistics, and computer science.

We‘ll explore how to perform mathematical operations on matrices later on. But first, let‘s learn how to actually create matrices in Python.

Creating NumPy Matrices

To work with matrices in Python, we‘ll use the NumPy library. NumPy is short for "Numerical Python" and is the de facto standard for scientific computing in Python. It provides an array object for efficient storage and manipulation of large, multi-dimensional datasets.

To get started, make sure you have NumPy installed:

pip install numpy

Then import it in your Python environment:

import numpy as np

The most common way to create a matrix is from a list of lists using the np.array() function:

A = np.array([[1, 2, 3], 
              [4, 5, 6], 
              [7, 8, 9]])

This creates a 3×3 NumPy array, which we assign to the variable A. Each sublist becomes a row of the matrix.

We can check the shape (dimensions) of the matrix using the .shape attribute:

print(A.shape)  # (3, 3)

This tells us that A has 3 rows and 3 columns.

In addition to np.array(), there are several other convenience functions for generating matrices of a specific form:

  • np.zeros(shape): Create a matrix filled with zeros
  • np.ones(shape): Create a matrix filled with ones
  • np.eye(N): Create an identity matrix with 1s on the diagonal and 0s elsewhere
  • np.diag(A): Extract the diagonal of a matrix A or construct a diagonal matrix from a vector
  • np.random.rand(rows, cols): Generate a matrix with random values between 0 and 1

For example:

Z = np.zeros((2,3))  
print(Z)
‘‘‘
[[0. 0. 0.]
 [0. 0. 0.]] 
‘‘‘

I = np.eye(3)
print(I)  
‘‘‘
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
‘‘‘

R = np.random.rand(2,4)
print(R)
‘‘‘  
[[0.37454012 0.95071431 0.73199394 0.59865848]
 [0.15601864 0.15599452 0.05808361 0.86617615]]
‘‘‘

By default, NumPy uses 64-bit floating point numbers. We can specify other data types like integers, floats, complex numbers, or even strings using the dtype parameter:

A = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int8) 
B = np.array([[1.2, 3.5], [6.1, 4.3]], dtype=np.float32)
C = np.array([[1, 2j], [3, 4j]], dtype=np.complex128)

Indexing and Slicing Matrices

Once you‘ve created a matrix, you‘ll need to be able to access its elements. We can use square bracket indexing to refer to individual entries, just like with Python lists:

A = np.array([[1, 2, 3], 
              [4, 5, 6], 
              [7, 8, 9]])

print(A[0, 0])  # 1
print(A[1, 1])  # 5  
print(A[2, 2])  # 9

Remember that indices start at 0, not 1! To modify an element, use the same syntax on the left side of an assignment:

A[0,0] = 10
print(A)
‘‘‘
[[10  2  3]
 [ 4  5  6]  
 [ 7  8  9]]
‘‘‘

We can use slicing to extract entire rows or columns as smaller matrices:

print(A[0, :])  # [10  2  3]
print(A[:, 1])  # [2 5 8]  

Slicing uses the syntax start:end:step where any of the values can be omitted:

  • A[0, :] means take the 0th row and all columns
  • A[:, 1] means take all rows and the 1st column
  • A[:2, :2] takes the top-left 2×2 submatrix
  • A[::2, ::2] takes every other row and column

We can even use boolean masks to select specific elements matching a condition:

B = np.random.randn(4, 4)  # random 4x4 matrix
mask = B > 0
print(B[mask])

This will select only the positive entries of B into a 1D array.

Matrix Arithmetic

The beauty of NumPy arrays is that we can efficiently perform mathematical operations on them. The most basic are element-wise addition, subtraction, multiplication, and division. Simply use the +, -, *, and / operators between two matrices of the same shape:

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

print(A + B)
‘‘‘
[[ 6  8]
 [10 12]]  
‘‘‘

print(A - B) 
‘‘‘
[[-4 -4]
 [-4 -4]]
‘‘‘

print(A * B)
‘‘‘  
[[ 5 12]
 [21 32]]
‘‘‘

print(A / B)  
‘‘‘
[[0.2        0.33333333]
 [0.42857143 0.5       ]]
‘‘‘

We can also perform these operations with a single number (scalar) and NumPy will automatically broadcast it to every element:

print(A + 1)
‘‘‘
[[2 3]  
 [4 5]]
‘‘‘

print(B / 2)
‘‘‘
[[2.5 3. ]
 [3.5 4. ]] 
‘‘‘

A @ B performs matrix multiplication, which has special rules based on the shapes of the input matrices. The number of columns in the first matrix must equal the number of rows in the second. The result will have the same number of rows as the first input and the same number of columns as the second input.

Mathematically, to compute the element C[i,j] of the matrix product, we take the dot product of the ith row of A with the jth column of B:

A = np.array([[1, 2, 3],
              [4, 5, 6]]) # 2x3

B = np.array([[10, 20], 
              [30, 40],
              [50, 60]]) # 3x2

C = A @ B

print(C)
‘‘‘
[[220 280]
 [490 640]]
‘‘‘

Here‘s how to compute the first element C[0,0] = 220 step-by-step:

  • Multiply A[0,0] B[0,0] = 1 10 = 10
  • Multiply A[0,1] B[1,0] = 2 30 = 60
  • Multiply A[0,2] B[2,0] = 3 50 = 150
  • Sum the three products: 10 + 60 + 150 = 220

We repeat this for every pair of rows from A and columns from B to fill in the entries of C.

Useful Matrix Functions

NumPy also provides a number of useful functions for operating on matrices:

  • np.transpose(A) or A.T: Swap rows and columns
  • np.linalg.inv(A): Compute matrix inverse
  • np.linalg.det(A): Compute determinant
  • np.linalg.eig(A): Compute eigenvalues and eigenvectors
  • np.linalg.solve(A, b): Solve system of linear equations Ax = b
  • np.dot(A, B): Alternative matrix multiplication function
  • A.sum(), A.min(), A.max(), A.mean(): Aggregate functions
  • np.apply_along_axis(func, axis, A): Apply a function across rows (axis=1) or columns (axis=0)

Here are a few examples:

A = np.array([[1, 2], 
              [3, 4]])

print(A.T)
‘‘‘
[[1 3]
 [2 4]]
‘‘‘

print(np.linalg.inv(A))
‘‘‘  
[[-2.   1. ]
 [ 1.5 -0.5]]
‘‘‘

v = np.array([1, -1])  
print(np.linalg.solve(A, v))
‘‘‘
[ 0. -1.]
‘‘‘ 

print(A.sum())  # 10
print(A.mean()) # 2.5

Applications of Matrices

Matrices have numerous real-world applications across science and engineering. Here are a few examples:

  • In image processing, a grayscale image can be represented as a 2D matrix where each entry is a pixel intensity value between 0-255. We can perform operations like smoothing, sharpening, and edge detection by applying filters (small matrices) to each pixel neighborhood.

  • In computer graphics, 3D objects and transformations (rotations, scaling, translation, etc.) are represented compactly using 4×4 matrices. Matrix multiplication is used to apply a sequence of transformations and project 3D coordinates onto a 2D screen.

  • In machine learning, matrices are the basic unit of data for training models. For example, a collection of N instances each with M features can be stored in an N x M matrix X. The model parameters form another matrix W, and predictions are computed by the matrix product X @ W.

  • Graphs and networks can be represented using adjacency matrices, where A[i,j] = 1 if nodes i and j are connected, and 0 otherwise. Matrix powers A^n give the number of n-step paths between each pair of nodes. Centrality measures and spectral clustering use the eigenvalues and eigenvectors of A.

  • Dynamical systems are often described by vectors of state variables (e.g. position, velocity, acceleration) that evolve over time according to a transition matrix. Markov chains are a simple model where each state depends only on the previous state, so the evolution is given by repeated matrix multiplication.

The list of applications goes on, including solving optimization problems, analyzing quantum systems, studying population dynamics, and much more. Matrices provide a powerful and compact language for describing and computing with all sorts of structured data.

Conclusion

In this article, we covered the basics of working with matrices in Python. The key steps are:

  1. Create a NumPy array from a nested list or using a special function
  2. Access and modify elements using indexing and slicing
  3. Perform mathematical operations like addition, multiplication, and linear algebra routines
  4. Apply matrices to real-world datasets and problems

Of course, there are many more advanced topics, like sparse matrices, tensor operations, and GPU computing, but NumPy provides a solid foundation that can take you far. I encourage you to explore the NumPy documentation for more details and examples.

With practice, matrix algebra will become a versatile tool in your scientific Python toolkit. It provides a concise and efficient way to describe all sorts of computational problems. In future articles, I‘ll delve into some of these applications in greater depth. Please leave a comment if there are any specific topics you‘d like me to cover!

Similar Posts