Mastering NumPy: Part 4(Array Broadcasting)

Nandeda Narayan
9 min readMay 24, 2023

--

This is the 5th blog post in our comprehensive series (Access all posts of this series here) on NumPy!

Note: Don’t forget to bookmark the full 50 examples series — Mastering NumPy: A 5 Parts Series to Master Numpy

Introduction

Array broadcasting is a powerful concept in NumPy that enables efficient element-wise operations between arrays of different shapes. It eliminates the need for explicit loops and enhances code readability and performance. In this blog post, we will explore ten examples of array broadcasting using NumPy, showcasing how it simplifies and accelerates array computations.

Examples:

1. Performing element-wise operations between arrays of different shapes using broadcasting.

Broadcasting in NumPy allows you to perform element-wise operations between arrays of different shapes by automatically aligning and extending the smaller array to match the shape of the larger array. Here’s an example that demonstrates broadcasting in NumPy:

import numpy as np

# Example arrays
a = np.array([1, 2, 3])
b = np.array([4, 5])

# Perform element-wise addition
result = a[:, np.newaxis] + b

print(result)

In this example, we have two arrays, a and b, with different shapes. a has a shape of (3,) and b has a shape of (2,).

To perform element-wise addition between these arrays, we use broadcasting. Here’s how it works:

  1. We add a new axis to array a using np.newaxis. This changes the shape of a from (3,) to (3,1).
  2. The smaller array b is extended to match the shape of the larger array a by repeating its elements along the new axis. The resulting shape of b becomes (2,1).
  3. Now, the arrays a and b have compatible shapes for broadcasting, and the element-wise addition is performed between them.
  4. The result is stored in the result array, which has a shape of (3,2), representing the element-wise addition of a and b.

The output of the above code will be:

[[5 6]
[6 7]
[7 8]]

As you can see, broadcasting allows us to perform element-wise operations between arrays of different shapes without explicitly resizing or repeating the smaller array. NumPy takes care of aligning the arrays and extending their dimensions as needed for the operation.

Here’s a simpler example of performing element-wise multiplication between arrays of different shapes using broadcasting:

import numpy as np

# Example arrays
a = np.array([1, 2, 3])
b = np.array([2])

# Perform element-wise multiplication
result = a * b

print(result)

In this example, we have an array a with shape (3,) and an array b with shape (1,).

To perform element-wise multiplication between these arrays, broadcasting is applied. Here’s how it works:

  1. Since b has a smaller size than a, it is automatically extended along the first dimension to match the shape of a.
  2. The value 2 in array b is broadcasted to become [2, 2, 2].
  3. The element-wise multiplication is performed between a and the broadcasted b.

The output of the above code will be:

[2 4 6]

2. Adding a scalar value to each element in an array using broadcasting

To add a scalar value to each element in an array using broadcasting, you can follow this example with NumPy:

import numpy as np

# Example array
arr = np.array([1, 2, 3, 4, 5])

# Scalar value
scalar = 10

# Add scalar value to each element
result = arr + scalar

print(result)
# [11 12 13 14 15]

In this example, we have an array arr with shape (5,) and a scalar value scalar of 10.

By simply performing the addition operation (+) between the array and the scalar value, NumPy automatically applies broadcasting to add the scalar value to each element of the array. The scalar value is extended to match the shape of the array during the operation.

As you can see, the scalar value 10 is added to each element in the array using broadcasting. Broadcasting simplifies the process of performing operations between arrays and scalar values, eliminating the need for explicit loops or vectorization.

3. Multiplying an array by a scalar using broadcasting

To multiply an array by a scalar using broadcasting in NumPy, you can use the following code example:

import numpy as np

# Example array
arr = np.array([1, 2, 3, 4, 5])

# Scalar value
scalar = 2

# Multiply array by scalar value
result = arr * scalar

print(result)
# [ 2 4 6 8 10]

In this example, we have an array arr with shape (5,) and a scalar value scalar of 2.

By performing the multiplication operation (*) between the array and the scalar value, NumPy automatically applies broadcasting to multiply each element of the array by the scalar value. The scalar value is extended to match the shape of the array during the operation.

As shown, each element in the array is multiplied by the scalar value of 2 using broadcasting.

4. Broadcasting an array along a specific axis using numpy.newaxis

In NumPy, you can use numpy.newaxis to insert a new axis into an array, effectively changing its shape and allowing for broadcasting along a specific axis. Here's an example that demonstrates how to broadcast an array along a specific axis using numpy.newaxis:

import numpy as np

# Example array
arr = np.array([1, 2, 3])

# Broadcast array along a new axis
broadcasted_arr = arr[:, np.newaxis]

print(broadcasted_arr)

# Output
# [[1]
# [2]
# [3]]

In this example, we have an array arr with shape (3,).

To broadcast the array along a new axis, we use np.newaxis to insert a new axis at the specified position. In this case, we insert a new axis at index 1, which corresponds to the rows of the array.

As you can see, the original array arr is broadcasted along a new axis, resulting in a new array broadcasted_arr with shape (3, 1). The values of the original array are now arranged as a column vector.

By broadcasting the array along a specific axis, you can perform operations with other arrays that have compatible shapes along that axis, enabling efficient element-wise calculations and broadcasting across different dimensions.

5. Performing operations between a one-dimensional and a two-dimensional array using broadcasting

import numpy as np

# One-dimensional array
arr1 = np.array([1, 2, 3])

# Two-dimensional array
arr2 = np.array([[4, 5, 6],
[7, 8, 9]])

# Perform addition using broadcasting
result = arr1 + arr2
print("Result (Addition):\n", result)

# Perform subtraction using broadcasting
result = arr2 - arr1
print("Result (Subtraction):\n", result)

# Perform multiplication using broadcasting
result = arr1 * arr2
print("Result (Multiplication):\n", result)

# Perform division using broadcasting
result = arr2 / arr1
print("Result (Division):\n", result)

Output:

Result (Addition):
[[ 5 7 9]
[ 8 10 12]]

Result (Subtraction):
[[3 3 3]
[6 6 6]]

Result (Multiplication):
[[ 4 10 18]
[ 7 16 27]]

Result (Division):
[[4. 2.5 2. ]
[7. 4. 3. ]]

In the above code, the operations of addition, subtraction, multiplication, and division are performed between the one-dimensional array arr1 and the two-dimensional array arr2 using broadcasting. The resulting array result contains the element-wise results of the operations. Broadcasting automatically aligns the shapes of the arrays to perform the operations correctly.

6. Broadcasting an array to match the shape of another array

You can use the numpy.broadcast_to() function to broadcast an array to match the shape of another array. Here's an example:

import numpy as np

# Array to be broadcasted
arr1 = np.array([1, 2, 3])

# Target array
arr2 = np.array([[4, 5, 6],
[7, 8, 9]])

# Broadcast arr1 to match the shape of arr2
broadcasted_arr1 = np.broadcast_to(arr1, arr2.shape)

print("Broadcasted Array:\n", broadcasted_arr1)

# Output
# Broadcasted Array:
# [[1 2 3]
# [1 2 3]]

In the above code, the numpy.broadcast_to() function is used to broadcast arr1 to match the shape of arr2. The arr1 array is broadcasted to a 2-dimensional array with the same shape as arr2, resulting in broadcasted_arr1. The elements of arr1 are repeated along the new dimensions to match the shape of arr2.

Note that numpy.broadcast_to() does not create a new array, but it returns a read-only view of the original array with the desired shape. If you modify elements in the broadcasted array, the corresponding elements in the original array will also be modified.

7. Applying conditional statements to an array using broadcasting

import numpy as np

# Input array
arr = np.array([1, 2, 3, 4, 5])

# Applying conditional statements using broadcasting
result = np.where(arr < 3, arr, 0)

print("Result:\n", result)

# Result:
# [1 2 0 0 0]

In the above code, the conditional statement arr < 3 checks if each element in the array arr is less than 3. Using broadcasting, the np.where() function applies the conditional statement element-wise. If the condition is True, the element is kept; otherwise, it is replaced with 0.

The resulting array result contains the modified elements based on the conditional statement. Elements less than 3 are retained, while elements greater than or equal to 3 are replaced with 0.

8. Broadcasting an array to perform element-wise logical operations.

import numpy as np

# Input arrays
arr1 = np.array([True, False, True])
arr2 = np.array([False, True, True])

# Element-wise logical AND operation
result_and = arr1 & arr2
print("Logical AND:\n", result_and)

# Element-wise logical OR operation
result_or = arr1 | arr2
print("Logical OR:\n", result_or)

# Element-wise logical NOT operation on arr1
result_not = ~arr1
print("Logical NOT (arr1):\n", result_not)

# Logical AND:
# [False False True]
# Logical OR:
# [ True True True]
# Logical NOT (arr1):
# [False True False]

In the above code, the element-wise logical operations of AND, OR, and NOT are performed between the arrays arr1 and arr2 using broadcasting.

The & operator performs the element-wise logical AND operation between corresponding elements of arr1 and arr2. The resulting array result_and contains the logical AND results.

Similarly, the | operator performs the element-wise logical OR operation between corresponding elements of arr1 and arr2. The resulting array result_or contains the logical OR results.

The ~ operator performs the element-wise logical NOT operation on arr1. The resulting array result_not contains the logical NOT results.

9. Broadcasting an array to compute element-wise power

To compute element-wise power of an array using numpy.power(), you can simply pass the array and the desired exponent as arguments to the function.

import numpy as np

arr = np.array([1, 2, 3, 4, 5]) # Example array
exponent = 2 # Desired exponent

result = np.power(arr, exponent) # Element-wise power computation

print(result)
# [ 1 4 9 16 25]

In this example, the numpy.power() function is used to compute the element-wise power of each element in the array arr with an exponent of 2. The resulting array result contains the computed values [1, 4, 9, 16, 25], which are the square of the corresponding elements in arr.

10. Performing matrix multiplication between arrays using broadcasting.

Performing matrix multiplication between arrays using broadcasting in NumPy can be achieved by appropriately reshaping the arrays to match the desired matrix dimensions.

import numpy as np

# Define the arrays
arr1 = np.array([[1, 2], [3, 4]]) # 2x2 matrix
arr2 = np.array([1, 2]) # 1x2 matrix

# Reshape arr2 to match the dimensions of arr1
arr2_reshaped = arr2.reshape((2, 1))

# Perform matrix multiplication using broadcasting
result = arr1 * arr2_reshaped

print(result)

# [[ 1 2]
# [ 6 8]]

In this example, the array arr1 represents a 2x2 matrix, and arr2 represents a 1x2 matrix. To perform matrix multiplication using broadcasting, we reshape arr2 to have dimensions 2x1 so that the shapes of arr1 and arr2_reshaped align for broadcasting.

Then, we perform element-wise multiplication between arr1 and arr2_reshaped, which results in the matrix multiplication between the two arrays. The resulting matrix result is [ [1*1, 2*1], [3*2, 4*2] ], which gives [[1, 2], [6, 8]].

Conclusion

In this blog post, we delved into the world of array broadcasting in NumPy. We explored various scenarios where broadcasting enables element-wise operations between arrays of different shapes, reducing the need for explicit loops and improving computational efficiency.

Next Blog Post

In the next blog post Mastering NumPy: Part 5(Advanced Features), we will dive into the advanced features of NumPy. We will explore masked arrays for handling missing or invalid values, sorting and interpolation techniques, vectorization, and more, showcasing the versatility and sophistication of the library.

Note: Don’t forget to bookmark the full 50 NumPy examples series — Mastering NumPy: A 5 Parts Series to Master Numpy

--

--