How to Perform Matrix Operations with NumPy

Categories:

How to Perform Matrix Operations with NumPy
Photo by Vlado Paunovic

 
NumPy is a powerful Python library that contains a large collection of mathematical functions, and supports the creation of matrices and multi-dimensional arrays to which these mathematical functions can be applied.

In this short tutorial, you will learn how to perform several of the most basic matrix operations with NumPy.

Matrices and Arrays in NumPy

In NumPy, a matrix is defined as a specialised array that is strictly 2-dimensional, and which retains its 2-dimensionality following the application of mathematical operations. A matrix of this type can be implemented using the np.matrix class, however NumPy no longer recommends use of this class as it may be removed in the future. The alternative option that is recommended by NumPy is to use the N-dimensional array type, ndarray.

The key difference between an ndarray and a matrix in NumPy is that the former can be of any dimensionality, and its use is not restricted to 2-dimensional operations.

Hence, in this tutorial we shall be focusing on implementing several basic matrix operations on 2-dimensional arrays, created using np.ndarray

Creating NumPy Arrays

Let’s first import the NumPy package and then proceed to create two, 2-dimensional arrays that are composed of two rows and three columns each. These arrays will be used in the ensuing examples of this tutorial:

# Import NumPy package
import numpy as np # Create arrays
a1 = np.array([[0, 1, 0], [2, 3, 2]])
a2 = np.array([[3, 4, 3], [5, 6, 5]])

The shape attribute lets us confirm the array’s dimensions:

# Print one of the arrays
print('Array 1:', '\n', a1, '\n Shape: \n’, a1.shape)

Output:

Array 1: [[0 1 0]
[2 3 2]] Shape: (2, 3)

Basic Array Operations

NumPy provides its own functions to perform element-wise addition, subtraction, division and multiplication of arrays. In addition, Numpy also leverages Python’s arithmetic operators by extending their functionality to handle element-wise array operations.

Let’s start with element-wise addition between the arrays a1 and a2 as an example.

Element-wise addition of two arrays can be achieved by making use of the np.add function or the overloaded + operator:

# Using np.add
func_add = np.add(a1, a2) # Using the + operator
op_add = a1 + a2

By printing out the results, it may be confirmed that they both produce the same output:

# Print results
print('Function: \n', func_add, '\n\n', 'Operator: \n', op_add)

Output:

Function: [[3 5 3]
[7 9 7]] Operator: [[3 5 3]
[7 9 7]]

However, if we had to time them, we can notice a small difference:

import numpy as np
import timeit def func(): a1 = np.array([[0, 1, 0], [2, 3, 2]])
a2 = np.array([[3, 4, 3], [5, 6, 5]])
np.add(a1, a2) def op(): a1 = np.array([[0, 1, 0], [2, 3, 2]])
a2 = np.array([[3, 4, 3], [5, 6, 5]])
a1 + a2 # Timing the functions over 100000 iterations
func_time = timeit.timeit(func, number=100000)
op_time = timeit.timeit(op, number=100000) # Print timing results
print('Function:', func_time, '\n', 'Operator:', op_time)

Output:

Function: 0.2588757239282131 Operator: 0.24321464297827333

Here it may be seen that the NumPy np.add function performs slightly slower than the + operator. This is mainly because the add function introduces type-checking to convert any array_like inputs (such as lists) into arrays before performing the addition operation. This, in turn, introduces an extra computational overhead over the + operator.

However, such measure also makes the np.add function less prone to error. For instance, applying np.add to inputs of type list still works (e.g. np.add([1, 1], [2, 2])), whereas applying the + operator results in list concatenation.

Similarly for element-wise subtraction (using np.subtract or -), division (using np.divide or /) and multiplication (using np.multiply or *), the NumPy functions perform type-checking, introducing a small computational overhead.

Several other operations that may come in handy include transposing and multiplying arrays.

Matrix transposition results in an orthogonal rotation of the matrix, and can be achieved using the np.transpose function (which includes type-checking) or the .T attribute:

# Using np.transpose
func_a1_T = np.transpose(a1) # Using the .T attribute
att_a1_T = a1.T

Matrix multiplication can be performed using the np.dot function or the @ operator (the latter implements the np.matmul function from Python 3.5 onwards):

# Using np.dot
func_dot = np.dot(func_a1_T, a2) # Using the @ operator
op_dot = func_a1_T @ a2

When working with 2-dimensional arrays, np.dot and np.matmul perform identically and both include type-checking.

Additional Resources

 
 

Stefania Cristina, PhD, is a Senior Lecturer with the Department of Systems and Control Engineering at the University of Malta. Her research interests lie within the domains of computer vision and machine learning.


Discover more from TechPros: Innovate, Learn & Connect

Subscribe to get the latest posts sent to your email.

Leave a Reply