How to Create an Identity Matrix in NumPy
An identity matrix is a square matrix with ones on the main diagonal and zeros everywhere else. It's the matrix equivalent of the number 1—multiply any matrix by the identity matrix, and you get the...
Key Insights
- Use
numpy.eye()when you need flexibility—rectangular matrices, offset diagonals, or non-standard configurations - Use
numpy.identity()when you want clean, readable code for standard square identity matrices - Always specify
dtypeexplicitly for large matrices to avoid unnecessary memory consumption with the default float64
What Is an Identity Matrix?
An identity matrix is a square matrix with ones on the main diagonal and zeros everywhere else. It’s the matrix equivalent of the number 1—multiply any matrix by the identity matrix, and you get the original matrix back unchanged.
# A 3x3 identity matrix looks like this:
# [[1, 0, 0],
# [0, 1, 0],
# [0, 0, 1]]
Identity matrices appear constantly in linear algebra, machine learning, and scientific computing. You’ll use them for matrix inversion verification, coordinate transformations, regularization terms in regression, and neural network weight initialization. NumPy gives you two primary functions to create them: numpy.eye() and numpy.identity(). Understanding when to use each saves you time and prevents subtle bugs.
Using numpy.eye() — The Flexible Option
The eye() function is your go-to for most identity matrix needs. It offers parameters that identity() doesn’t, making it suitable for edge cases and non-standard requirements.
Basic Syntax
numpy.eye(N, M=None, k=0, dtype=float, order='C')
N: Number of rowsM: Number of columns (defaults to N if not specified)k: Diagonal offset (0 is main diagonal, positive shifts up, negative shifts down)dtype: Data type of the output arrayorder: Memory layout (‘C’ for row-major, ‘F’ for column-major)
Creating Standard Identity Matrices
import numpy as np
# Basic 3x3 identity matrix
I3 = np.eye(3)
print(I3)
# Output:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 4x4 identity matrix with integer dtype
I4_int = np.eye(4, dtype=int)
print(I4_int)
# Output:
# [[1 0 0 0]
# [0 1 0 0]
# [0 0 1 0]
# [0 0 0 1]]
Rectangular Identity-Like Matrices
Sometimes you need a non-square matrix with ones on the diagonal. This is common in certain linear algebra operations and data augmentation scenarios.
# 3 rows, 5 columns
rect_matrix = np.eye(3, 5)
print(rect_matrix)
# Output:
# [[1. 0. 0. 0. 0.]
# [0. 1. 0. 0. 0.]
# [0. 0. 1. 0. 0.]]
# 5 rows, 3 columns
tall_matrix = np.eye(5, 3)
print(tall_matrix)
# Output:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]
# [0. 0. 0.]
# [0. 0. 0.]]
Offset Diagonals with the k Parameter
The k parameter shifts the diagonal. This is useful for creating banded matrices, shift operators, or building blocks for more complex matrix structures.
# Main diagonal (k=0, the default)
print(np.eye(4, k=0, dtype=int))
# Output:
# [[1 0 0 0]
# [0 1 0 0]
# [0 0 1 0]
# [0 0 0 1]]
# Upper diagonal (k=1)
print(np.eye(4, k=1, dtype=int))
# Output:
# [[0 1 0 0]
# [0 0 1 0]
# [0 0 0 1]
# [0 0 0 0]]
# Lower diagonal (k=-1)
print(np.eye(4, k=-1, dtype=int))
# Output:
# [[0 0 0 0]
# [1 0 0 0]
# [0 1 0 0]
# [0 0 1 0]]
# Creating a tridiagonal-like structure
tridiag = np.eye(5, k=-1) + np.eye(5) + np.eye(5, k=1)
print(tridiag)
# Output:
# [[1. 1. 0. 0. 0.]
# [1. 1. 1. 0. 0.]
# [0. 1. 1. 1. 0.]
# [0. 0. 1. 1. 1.]
# [0. 0. 0. 1. 1.]]
Using numpy.identity() — The Simple Option
When you need a standard square identity matrix and nothing else, numpy.identity() communicates your intent more clearly.
Basic Syntax
numpy.identity(n, dtype=None)
That’s it. Two parameters. No diagonal offsets, no rectangular options—just a clean function for the most common case.
Basic Usage
import numpy as np
# 3x3 identity matrix
I3 = np.identity(3)
print(I3)
# Output:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# With explicit dtype
I_float32 = np.identity(4, dtype=np.float32)
I_int = np.identity(4, dtype=int)
I_complex = np.identity(3, dtype=complex)
print(f"float32 identity:\n{I_float32}")
print(f"int identity:\n{I_int}")
print(f"complex identity:\n{I_complex}")
The function name itself documents what you’re doing. When someone reads np.identity(5), there’s zero ambiguity. Compare that to np.eye(5), which could theoretically have offset diagonals or be rectangular—you’d need to check the parameters to be sure.
Practical Differences: eye() vs identity()
Here’s when to use each:
| Feature | numpy.eye() |
numpy.identity() |
|---|---|---|
| Square matrices | ✓ | ✓ |
| Rectangular matrices | ✓ | ✗ |
| Diagonal offset | ✓ | ✗ |
| Code clarity for standard identity | Good | Better |
| Memory layout control | ✓ | ✗ |
Use identity() when:
- You need a standard square identity matrix
- Code readability matters (it usually does)
- You want to signal intent clearly to other developers
Use eye() when:
- You need a rectangular matrix
- You need an offset diagonal
- You’re building complex matrix structures
- You need control over memory layout
In practice, I default to identity() for standard cases and reach for eye() only when I need its extra features.
Common Use Cases
Verifying Matrix Inversion
The most common use of identity matrices is verifying that matrix inversion worked correctly. If A @ A_inv equals the identity matrix (within floating-point tolerance), your inversion succeeded.
import numpy as np
# Create a random invertible matrix
A = np.array([[4, 7], [2, 6]])
# Compute inverse
A_inv = np.linalg.inv(A)
# Verify: A @ A_inv should equal identity
result = A @ A_inv
I = np.identity(2)
print("A @ A_inv:")
print(result)
print("\nIs close to identity?", np.allclose(result, I))
# Output: True
Initializing Transformation Matrices
In computer graphics and robotics, you often start with an identity matrix and modify it to represent transformations.
import numpy as np
def create_translation_matrix_2d(tx, ty):
"""Create a 2D translation matrix using homogeneous coordinates."""
T = np.identity(3)
T[0, 2] = tx # x translation
T[1, 2] = ty # y translation
return T
def create_scale_matrix_2d(sx, sy):
"""Create a 2D scaling matrix."""
S = np.identity(3)
S[0, 0] = sx # x scale
S[1, 1] = sy # y scale
return S
# Translate by (5, 3) then scale by (2, 2)
T = create_translation_matrix_2d(5, 3)
S = create_scale_matrix_2d(2, 2)
# Combine transformations
combined = S @ T
print("Translation matrix:")
print(T)
print("\nScale matrix:")
print(S)
print("\nCombined transformation:")
print(combined)
Regularization in Machine Learning
Ridge regression adds a scaled identity matrix to prevent overfitting. This is called L2 regularization.
import numpy as np
def ridge_regression(X, y, lambda_reg=1.0):
"""
Closed-form solution for ridge regression:
w = (X^T X + λI)^(-1) X^T y
"""
n_features = X.shape[1]
I = np.identity(n_features)
XtX = X.T @ X
XtX_regularized = XtX + lambda_reg * I
w = np.linalg.inv(XtX_regularized) @ X.T @ y
return w
# Example usage
X = np.random.randn(100, 5)
y = np.random.randn(100)
weights = ridge_regression(X, y, lambda_reg=0.5)
print("Ridge regression weights:", weights)
Performance Considerations
For small matrices, performance differences are negligible. For large matrices, dtype selection matters significantly.
import numpy as np
# Compare memory usage for different dtypes
sizes = [100, 1000, 5000]
for size in sizes:
I_float64 = np.identity(size, dtype=np.float64)
I_float32 = np.identity(size, dtype=np.float32)
I_int8 = np.eye(size, dtype=np.int8)
print(f"\n{size}x{size} identity matrix:")
print(f" float64: {I_float64.nbytes / 1024 / 1024:.2f} MB")
print(f" float32: {I_float32.nbytes / 1024 / 1024:.2f} MB")
print(f" int8: {I_int8.nbytes / 1024 / 1024:.2f} MB")
For a 5000x5000 matrix, float64 uses 200 MB while int8 uses only 25 MB. If you’re creating many identity matrices or working with memory constraints, choose your dtype deliberately rather than accepting the float64 default.
Both eye() and identity() have similar performance characteristics—they’re both O(n²) for creating an n×n matrix. The choice between them should be based on functionality needs and code clarity, not speed.
Conclusion
Creating identity matrices in NumPy is straightforward once you know which function to use:
numpy.identity(n): Use this for standard square identity matrices. It’s cleaner and communicates intent better.numpy.eye(N, M, k): Use this when you need rectangular matrices, offset diagonals, or memory layout control.
For most day-to-day work, identity() is the right choice. Reserve eye() for cases where you genuinely need its additional parameters. And regardless of which function you use, always consider specifying dtype explicitly—especially for large matrices where the default float64 might waste memory you can’t afford.