Introduction
Welcome back! In the previous lesson, you built a strong foundation in NumPy by learning how to create, index, slice, and reshape ndarrays. You now understand the structure of these powerful arrays and how to access and organize the data within them. This mastery of data manipulation is the first step.
Today, we move to data computation. This lesson focuses on the learning outcome: Perform element-wise and matrix operations on NumPy arrays. We will explore the two fundamental ways NumPy performs calculations: one-on-one operations across corresponding elements, and the more complex, rule-based operations of linear algebra.
For your goal of building advanced AI, this is a critical step. The complex algorithms that power machine learning models are, at their core, a series of highly optimized mathematical operations on large arrays of data. Today, you'll learn the "verbs" of that mathematical language.
1. Element-Wise Operations
The most common type of operation in NumPy is an element-wise operation. This means that for two arrays of the same shape, an operation is applied to each pair of corresponding elements to produce a new array of the same shape.
Let's start with the basic arithmetic operators: +, -, *, /.
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[10, 20], [30, 40]])
# Element-wise addition
print("Addition:\n", a + b)
# Element-wise subtraction
print("\nSubtraction:\n", a - b)
Now, let's focus on multiplication. It is crucial to understand that the standard * operator in NumPy performs element-wise multiplication, not matrix multiplication.

This concept is fundamental. To dive deeper, the following text provides excellent examples and clarifies the performance benefits of these "vectorized" operations over standard Python loops.
NumPy Fundamentals for Data Science and Machine Learning
Let's read a short section from the "NumPy Fundamentals" article. It clearly explains how basic arithmetic operations are performed element-wise and contrasts this with scalar multiplication.
Read the subsection titled "Array arithmetic". Pay close attention to the code examples for addition, subtraction, multiplication, and division. Notice how the operations work on each element independently.
Broadcasting: Operations with Mismatched Shapes
What happens if you try to perform an operation on arrays with different shapes? In the last lesson, we saw that for indexing and assignment, this could lead to errors. However, for arithmetic operations, NumPy has a powerful mechanism called broadcasting.
Broadcasting allows NumPy to perform operations on arrays of different (but compatible) shapes. The most common case is operating on an array with a single number (a scalar).
a = np.array([[1, 2, 3], [4, 5, 6]])
# Multiply every element in 'a' by 10
result = a * 10
print(result)
Output:
[[10 20 30]
[40 50 60]]
Conceptually, NumPy "stretches" or "duplicates" the scalar 10 to create an array [[10, 10, 10], [40, 50, 60]] so that it can perform an element-wise operation. This is done without actually using extra memory, making it highly efficient.
The "Scipy lecture notes" provide a fantastic visual and a practical example of how this works.
Numerical operations on arrays — Scipy lecture notes
This resource provides a very clear explanation of broadcasting with helpful diagrams.
Read the section "Broadcasting". Focus on the diagram that shows a (4,3) array being added to a (1,3) array. This visualizes how the smaller array is 'stretched' to match the larger one. Also, note the useful trick of using np.newaxis to make arrays compatible for broadcasting.
Broadcasting has a specific set of rules, but the key idea is that dimensions are compared from right to left, and they must either be equal, or one of them must be 1.
2. Matrix Multiplication
While element-wise multiplication is useful, the foundation of linear algebra and most machine learning algorithms is matrix multiplication, also known as the dot product.
Given your BTech background, you'll likely recall the rule for matrix multiplication: to multiply matrix A by matrix B, the number of columns in A must equal the number of rows in B.
If A has shape and B has shape , their product C will have shape .
In NumPy, you can perform matrix multiplication in two ways:
- The
np.dot()function:np.dot(A, B) - The
@operator:A @ B(This is the modern, preferred syntax)
Let's watch a video that breaks this down. It first reviews element-wise multiplication, then provides an excellent visual walkthrough of how matrix multiplication is calculated, before finally showing the Python code.
Multiplication of Matrix Using Numpy - Python Tutorial
This video from DataMites clearly distinguishes element-wise from matrix multiplication and provides a step-by-step visual explanation of the dot product calculation.
Watch from 01:54 to 07:13. The first part (until 02:38) reinforces the concept of element-wise multiplication using the * operator. The core of the clip (02:38 to 06:10) provides a manual, visual calculation of a dot product. This aligns perfectly with your theory-first preference. The final part (from 06:10) shows you how to implement this easily with np.dot() and np.matmul() (which is equivalent to the @ operator).
3. Other Essential Matrix Operations
Besides multiplication, there are a few other operations that are fundamental to linear algebra and data science.
Transpose
The transpose of a matrix flips it over its diagonal. It switches the row and column indices. A matrix with shape (m, n) becomes a matrix with shape (n, m). This is often used to make matrix dimensions compatible for multiplication. In NumPy, you can get the transpose using the .T attribute.
A = np.array([[1, 2, 3],
[4, 5, 6]])
print("Original A (shape", A.shape, "):\n", A)
print("\nTranspose of A (shape", A.T.shape, "):\n", A.T)
Inverse
The inverse of a square matrix , denoted , is a matrix such that when multiplied by , it results in the identity matrix (a matrix of ones on the diagonal and zeros elsewhere).
Finding the inverse is crucial for solving systems of linear equations. You can compute it using np.linalg.inv().
To see a quick demonstration of these operations in code, let's watch two short clips.
Python Tutorial: Matrix Operations using Numpy for Absolute Beginners
This video from Mr. STEM EDU TV provides quick, clear demonstrations of finding the inverse and transpose of a matrix.
First, watch from 05:32 to 06:10 to see how np.linalg.inv() is used to find the inverse and verify the result. Then, watch from 07:07 to 07:32 to see how to transpose a matrix with np.transpose() (which is the same as the .T attribute).
Note: Not all matrices have an inverse. A matrix that does not have an inverse is called a singular or degenerate matrix. Trying to compute the inverse of a singular matrix will result in a LinAlgError.
Your Turn: Practice Exercise
Time to apply these concepts. This exercise will challenge you to distinguish between element-wise and matrix operations and use the correct syntax for each.
Task (5-10 minutes):
- Create a 2x3 NumPy array
Awith values from 1 to 6. - Create a 3x2 NumPy array
Bwith values from 7 to 12. - Calculate the matrix product of
AandB, storing the result in a new arrayC. PrintCand its shape. - Try to compute the element-wise product of
AandB(A * B). This will fail. In a comment, briefly explain why. - Calculate the matrix product of
BandA, storing it inD. IsDthe same asC? This demonstrates that matrix multiplication is not commutative. - Create a new 2x2 array
Ewith random integer values between 1 and 5. - Compute the element-wise product of
CandE.
Click to see a possible solution
import numpy as np
# 1. Create array A
A = np.arange(1, 7).reshape(2, 3)
print("A:\n", A)
# 2. Create array B
B = np.arange(7, 13).reshape(3, 2)
print("\nB:\n", B)
# 3. Calculate matrix product C = A @ B
C = A @ B
print("\nC (A @ B):\n", C)
print("Shape of C:", C.shape)
# 4. Attempt element-wise product
# A * B
# This fails because element-wise operations require the arrays to have the same shape.
# A has shape (2, 3) and B has shape (3, 2), so they are not compatible for a '*' operation.
# 5. Calculate matrix product D = B @ A
D = B @ A
print("\nD (B @ A):\n", D)
print("Is C equal to D?", np.array_equal(C, D)) # Will be False
# 6. Create random array E
E = np.random.randint(1, 6, size=(2, 2))
print("\nE:\n", E)
# 7. Compute element-wise product of C and E
result = C * E
print("\nElement-wise product of C and E:\n", result)
Conclusion
Excellent work. You have now learned how to perform the fundamental computations that drive numerical analysis and machine learning in Python.
Key Takeaways:
- Element-wise operations (
+,-,*,/) apply an operation to corresponding elements in arrays of the same shape. - The
*operator performs element-wise multiplication, not matrix multiplication. - Broadcasting is NumPy's mechanism for performing operations on arrays of different but compatible shapes, like an array and a scalar.
- Matrix multiplication (dot product) follows the rules of linear algebra and is performed using the
@operator ornp.dot(). The dimensions must be compatible(m, n) @ (n, p). - Other key operations include finding the transpose (
.T) and inverse (np.linalg.inv()) of a matrix.
Preview of the Next Lesson:
So far, we've worked with NumPy's powerful but somewhat abstract ndarray. Real-world data, however, is often messy and comes with labels, like column headers in a spreadsheet. In the next lesson, "Load, inspect, and select data in pandas DataFrames", we will introduce the pandas library. Pandas is built on top of NumPy and provides a data structure called a DataFrame, which is perfectly designed for handling the structured, tabular data you'll encounter in almost every AI project.