Hello! Welcome to the final lesson in our module on Linear Algebra.
In our previous lessons, we've built a strong theoretical foundation, understanding concepts like matrix multiplication, determinants, inverses, eigenvalues, and even the powerful Singular Value Decomposition (SVD). The last lesson focused on the theory and manual calculation of SVD.
Today, we transition from theory to practice. This lesson is all about implementation. Our goal is to master the practical application of these concepts using Python's NumPy library, a skill that is absolutely essential for any data scientist or ML engineer. By the end of this lesson, you will be able to confidently use NumPy to compute determinants, inverses, eigenvalues, and SVD of matrices.
This is the bridge between the mathematical equations we've studied and the code you will write to solve real-world problems.
1. The numpy.linalg Module: Your Linear Algebra Toolkit
NumPy, which you're already familiar with for creating and manipulating arrays, has a powerful submodule dedicated to linear algebra: numpy.linalg. This module contains highly optimized functions for most of the standard linear algebra operations.
To get a quick overview of what's inside, let's look at an introductory resource.
This article from Tutorialspoint provides a great introduction to NumPy's linear algebra capabilities.
Read the introduction and review the table of functions under the 'Linear Algebra in NumPy' section. You don't need to click on the individual links; just get a sense of the functions available. We will be focusing on determinant, inv, eig, and svd in this lesson.
As you can see, NumPy provides a straightforward, function-based approach to performing complex matrix calculations. Let's dive into using them.
2. Determinant and Inverse
Remember that the determinant is a scalar value that tells us important properties about a square matrix, most notably whether it's invertible. A non-zero determinant means an inverse exists. The inverse of a matrix , denoted , is the matrix that, when multiplied by , yields the identity matrix.
NumPy makes calculating these trivial.
- Determinant:
np.linalg.det(A) - Inverse:
np.linalg.inv(A)
Let's see this in action. The following resource shows clear, simple examples for both.
This section of the Tutorialspoint article provides code examples for computing the determinant and inverse.
Read the subsections 'Computing the Determinant' and 'Computing the Inverse'. Pay attention to the function calls and the resulting outputs.
Now, let's combine these concepts in a single code block. We'll define a matrix, calculate its determinant, and then, if possible, find its inverse.
import numpy as np
# A non-singular (invertible) matrix
A = np.array([[4, 7],
[2, 6]])
# A singular (non-invertible) matrix
B = np.array([[2, 4],
[3, 6]])
# --- Calculate Determinant ---
det_A = np.linalg.det(A)
det_B = np.linalg.det(B)
print(f"Matrix A:\n{A}")
print(f"Determinant of A: {det_A:.2f}") # Using f-string to format output
print("-" * 20)
print(f"Matrix B:\n{B}")
print(f"Determinant of B: {det_B:.2f}")
print("-" * 20)
# --- Calculate Inverse ---
print("Calculating inverse of A...")
inv_A = np.linalg.inv(A)
print(f"Inverse of A:\n{inv_A}")
# Let's verify that A @ A_inv is the identity matrix
identity = A @ inv_A
print(f"\nVerification (A @ A_inv):\n{np.round(identity, 2)}") # Round to handle tiny floating-point errors
print("-" * 20)
# --- Attempt to invert a singular matrix ---
print("Attempting to calculate inverse of B...")
try:
inv_B = np.linalg.inv(B)
print(f"Inverse of B:\n{inv_B}")
except np.linalg.LinAlgError as e:
print(f"Could not compute inverse of B. Reason: {e}")
Notice two key things in the code above:
- The determinant of
Ais(4*6) - (7*2) = 24 - 14 = 10, which is non-zero. The determinant ofBis(2*6) - (4*3) = 12 - 12 = 0. - Trying to compute the inverse of the singular matrix
Bresults in aLinAlgError. This is NumPy's way of telling you the operation is mathematically impossible.
Test your understanding!
Given the matrix C = np.array([[3, 1], [1, 2]]).
- Without running the code, what do you expect the determinant to be?
- Write the Python code to compute its determinant and inverse using NumPy.
- Verify that
C @ C_invgives the identity matrix.
Show answer
- The determinant is
(3 * 2) - (1 * 1) = 6 - 1 = 5. - Here is the Python code:
import numpy as np C = np.array([[3, 1], [1, 2]]) # Calculate determinant det_C = np.linalg.det(C) print(f"Determinant of C: {det_C}") # Calculate inverse inv_C = np.linalg.inv(C) print(f"Inverse of C:\n{inv_C}") # Verification identity_check = C @ inv_C print(f"\nVerification (C @ C_inv):\n{np.round(identity_check)}")
3. Eigenvalues and Eigenvectors
As we learned, for a square matrix , an eigenvector is a special vector that, when transformed by , only changes in scale, not direction. The scaling factor is the eigenvalue. This is captured by the equation .
In NumPy, we can find both the eigenvalues and the corresponding eigenvectors using a single function: np.linalg.eig(A).
This function returns a tuple of two arrays:
- A 1D array of eigenvalues ().
- A 2D array where each column is the eigenvector () corresponding to the eigenvalue at the same index in the first array.
Let's review a resource that demonstrates this.
The 'Eigenvalues and Eigenvectors' section of the Tutorialspoint article shows exactly how to use np.linalg.eig() and interpret its output.
Read this section carefully. Note how the two returned values, eigenvalues and eigenvectors, are unpacked from the function's output.
Let's write our own code to demonstrate this and, more importantly, to verify the fundamental relationship .
import numpy as np
A = np.array([[1, -3, 3],
[3, -5, 3],
[6, -6, 4]])
print(f"Matrix A:\n{A}\n")
# Compute eigenvalues and eigenvectors
eigenvalues, eigenvectors = np.linalg.eig(A)
print(f"Eigenvalues (lambda):\n{eigenvalues}\n")
print(f"Eigenvectors (v) [as columns]:\n{eigenvectors}\n")
# --- Verification ---
# Let's check the relationship for the first eigenvalue/eigenvector pair.
lambda_1 = eigenvalues[0]
v_1 = eigenvectors[:, 0] # Get the first column as the first eigenvector
# Calculate A @ v
Av = A @ v_1
# Calculate lambda * v
lambda_v = lambda_1 * v_1
print("-" * 20)
print("Verifying A*v = lambda*v for the first pair:\n")
print(f"A @ v_1 = {np.round(Av, 2)}")
print(f"lambda_1 * v_1 = {np.round(lambda_v, 2)}\n")
# np.allclose() is the best way to check if two arrays are element-wise equal within a tolerance
print(f"Are they close? {np.allclose(Av, lambda_v)}")
This verification step is crucial. It confirms that the values returned by NumPy are not just abstract numbers, but that they correctly satisfy the defining equation of eigenvalues and eigenvectors.
4. Singular Value Decomposition (SVD)
In the previous lesson, we explored the theory of SVD, which decomposes any matrix (even non-square ones) into the product of three other matrices: .
We also had a first look at the numpy.linalg.svd() function. Now, let's solidify that practical knowledge. As a refresher, the function returns three components:
U: The matrix of left singular vectors.s: A 1D array of the singular values (the diagonal of ).Vt: The transposed matrix of right singular vectors ().
To reinforce how this works in a real coding environment, let's revisit the practical implementation part of the video from our last lesson.
Easiest Way to Understanding Singular Value Decomposition (SVD) with Python: numpy.linalg.svd
The 'Dr. Data Science' video has an excellent step-by-step implementation of SVD in a Python notebook. Watching it again will help cement the practical workflow.
Watch the coding demonstration from 20:38 to 27:40. Focus on how the svd function is called and how the shapes of the output matrices (U, s, and Vt) are inspected. Pay close attention to the full_matrices parameter.
One of the most important practical steps with np.linalg.svd is reconstructing the full matrix from the 1D array of singular values s so you can verify the decomposition.
Here is a complete example that puts it all together:
import numpy as np
# A rectangular matrix
A = np.array([[1, 1, 0],
[0, 1, 1]])
print(f"Original Matrix A (shape {A.shape}):\n{A}\n")
# Perform SVD
U, s, Vt = np.linalg.svd(A)
print(f"U (shape {U.shape}):\n{np.round(U, 2)}\n")
print(f"Singular values (s): {np.round(s, 2)}\n")
print(f"Vt (shape {Vt.shape}):\n{np.round(Vt, 2)}\n")
# To reconstruct A, we must build the Sigma matrix.
# It has the same shape as A, with the singular values on its diagonal.
Sigma = np.zeros(A.shape)
# The singular values go on the diagonal of a square sub-matrix
Sigma[:min(A.shape), :min(A.shape)] = np.diag(s)
print(f"Reconstructed Sigma (shape {Sigma.shape}):\n{np.round(Sigma, 2)}\n")
# Reconstruct the original matrix
A_reconstructed = U @ Sigma @ Vt
print(f"Reconstructed Matrix A:\n{np.round(A_reconstructed, 2)}\n")
print(f"Verification successful? {np.allclose(A, A_reconstructed)}")
Being able to decompose a matrix with svd and then correctly reconstruct it demonstrates a complete understanding of the practical workflow, which is a key skill for many data science applications like recommendation systems and dimensionality reduction.
Conclusion
Excellent work! You have now successfully completed the Linear Algebra module. You've journeyed from basic vector and matrix operations to advanced decomposition techniques, and most importantly, you've now translated that theory into practical coding skills with NumPy.
Key Takeaways:
- The
numpy.linalgmodule is the primary tool for performing linear algebra operations in Python. - Determinant:
np.linalg.det()computes the determinant of a square matrix. A non-zero result indicates the matrix is invertible. - Inverse:
np.linalg.inv()computes the inverse of an invertible matrix. It will raise aLinAlgErrorfor a singular (non-invertible) matrix. - Eigen-decomposition:
np.linalg.eig()returns the eigenvalues and corresponding eigenvectors of a square matrix. - SVD:
np.linalg.svd()decomposes any matrix into ,s(singular values), and , a cornerstone for many advanced algorithms.
You are now equipped to handle the linear algebra problems you will encounter in your GATE preparation and beyond.
Preview of the Next Lesson:
We are now moving on to the next major pillar of mathematics for data science: Calculus. In our next lesson, we will begin the "Calculus for Optimization" module by learning how to compute derivatives of polynomial, exponential, logarithmic, and trigonometric functions. This will be the first step toward understanding how machine learning models "learn" by minimizing error, a process driven by calculus.