NumPy
What I do
I provide fundamental numerical computing capabilities for Python through powerful N-dimensional array objects and mathematical functions. I enable efficient array operations, linear algebra computations, random number generation, Fourier transforms, and statistical calculations. I am the backbone of scientific computing in Python and serve as the foundation for pandas, scikit-learn, and other data science libraries.
When to use me
- Performing numerical computations on large datasets
- Working with multi-dimensional arrays and matrices
- Implementing mathematical and statistical operations
- Linear algebra operations (matrix multiplication, eigenvalues, decompositions)
- Random sampling and probability distributions
- Signal processing and Fourier analysis
- Image processing (as multi-dimensional arrays)
- Performance-critical numerical code
Core Concepts
Arrays
- ndarray: N-dimensional array object with homogeneous data types
- Shape: Dimensions of the array (e.g., (1000, 50) for 1000 rows, 50 columns)
- Data Types: int8-uint64, float16-float128, complex, bool, object
- Memory Layout: C-contiguous (row-major) or Fortran-contiguous (column-major)
Array Creation
- From scratch:
np.zeros(), np.ones(), np.empty(), np.arange(), np.linspace()
- From data:
np.array(), np.asarray(), np.fromfunction()
- Random arrays:
np.random.rand(), np.random.randint(), np.random.randn()
- Special matrices:
np.eye(), np.identity(), np.diag()
Indexing and Slicing
- Basic indexing: Single element
arr[0, 0], slices arr[1:5, :]
- Boolean indexing:
arr[arr > 0] for filtering
- Fancy indexing:
arr[[0, 2, 5]] for multiple indices
- Advanced indexing: Integer arrays
arr[np.newaxis, :]
Broadcasting
- Automatic expansion of arrays with different shapes for element-wise operations
- Rule 1: Dimensions match from right to left
- Rule 2: Dimensions of size 1 can be stretched to match
- Enables vectorized operations without explicit loops
Vectorization
- ufuncs: Universal functions for element-wise operations (np.add, np.multiply)
- Reduction operations:
np.sum(), np.mean(), np.max(), np.min()
- Accumulation:
np.cumsum(), np.cumprod()
- Sorting:
np.sort(), np.argsort(), np.partition()
Code Examples (Python)
import numpy as np
# Array creation
arr = np.array([1, 2, 3, 4, 5])
zeros = np.zeros((3, 4)) 3), dtype=int)
arange = np.arange(0, 10, 2)
linspace = np.linspace(0, 1, 100)
random = np.random.rand(1000)
random_normal = np.random.randn(1000)
random_int = np.random.randint(0, 100, (5, 5))
identity = np.eye(3)
diagonal = np.diag([1, 2, 3])
# Array properties
arr.shape # (5,) or (rows, cols)
arr.dtype # dtype('int64')
arr.ndim # Number of dimensions
arr.size # Total elements
arr.nbytes # Memory usage in bytes
# Reshaping
arr = np.arange(12)
reshaped = arr.reshape(3, 4)
flattened = reshaped.ravel()
transposed = reshaped.T
newaxis = arr[:, np.newaxis]
# Indexing
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr[0, 0] # First element: 1
arr[0] # First row: [1, 2, 3]
arr[:, 0] # First column: [1, 4, 7]
arr[1:3, 1:3] # Sub-array
arr[arr > 5] # Boolean indexing: [6, 7, 8, 9]
arr[[0, 2], [0, 2]] # Fancy indexing: [1, 9]
# Mathematical operations
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
np.add(arr1, arr2) # [5, 7, 9]
np.multiply(arr1, arr2) # [4, 10, 18]
np.divide(arr1, arr2) # [0.25, 0.4, 0.5]
np.power(arr1, 2) # [1, 4, 9]
np.sqrt(arr1) # [1.0, 1.414, 1.732]
np.exp(arr1) # [2.718, 7.389, 20.086]
np.log(arr1) # [0.0, 0.693, 1.099]
# Broadcasting
arr1 = np.array([[1], [2], [3]]) # (3, 1)
arr2 = np.array([4, 5, 6]) # (3,)
result = arr1 + arr2 # [[5, 6, 7], [6, 7, 8], [7, 8, 9]]
# Reductions
arr = np.array([1, 2, 3, 4, 5])
np.sum(arr) # 15
np.mean(arr) # 3.0
np.std(arr) # 1.414...
np.var(arr) # 2.0
np.min(arr) # 1
np.max(arr) # 5
np.argmax(arr) # 4
np.median(arr) # 3.0
np.percentile(arr, 75) # 4.0
# Axis-based operations
matrix = np.array([[1, 2, 3], [4, 5, 6]])
np.sum(matrix, axis=0) # Column sums: [5, 7, 9]
np.sum(matrix, axis=1) # Row sums: [6, 15]
np.mean(matrix, axis=1) # Row means: [2.0, 5.0]
# Linear algebra
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
np.dot(A, B) # Matrix multiplication
A @ B # Same as above
np.linalg.det(A) # Determinant: -2
np.linalg.inv(A) # Inverse
np.linalg.eig(A) # Eigenvalues and eigenvectors
np.linalg.solve(A, np.array([5, 6])) # Solve Ax = b
np.linalg.svd(A) # Singular value decomposition
np.linalg.qr(A) # QR decomposition
np.linalg.norm(A) # Matrix/vector norm
# Random number generation
np.random.seed(42) # Set seed
np.random.rand(5) # Uniform [0, 1)
np.random.randn(5) # Standard normal
np.random.randint(0, 10, 5) # Random integers
np.random.uniform(0, 1, 5) # Explicit uniform
np.random.normal(0, 1, 5) # Explicit normal
np.random.choice([1, 2, 3, 4, 5], 3, replace=False) # Without replacement
np.random.permutation(5) # Permutation
# Distributions
np.random.binomial(10, 0.5, 100) # Binomial
np.random.poisson(5, 100) # Poisson
np.random.exponential(1, 100) # Exponential
np.random.uniform(0, 1, 100) # Uniform
np.random.normal(0, 1, 100) # Normal
# Sorting
arr = np.array([3, 1, 4, 1, 5, 9, 2])
np.sort(arr) # Sorted array
np.argsort(arr) # Indices
np.partition(arr, 3) # Partition around 3rd element
# Set operations
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([3, 4, 5, 6, 7])
np.union1d(arr1, arr2) # [1, 2, 3, 4, 5, 6, 7]
np.intersect1d(arr1, arr2) # [3, 4, 5]
np.setdiff1d(arr1, arr2) # [1, 2]
Best Practices
Use vectorization: Replace Python loops with NumPy vectorized operations for 10-100x speedup.
Pre-allocate arrays: Create arrays with known sizes before loops instead of appending.
Use appropriate dtypes: Choose smaller dtypes (float32 instead of float64) when precision permits.
Avoid copies: Use views (reshape, strides) instead of copies when possible.
Use in-place operations: arr += 5 instead of arr = arr + 5 to avoid temporary arrays.
Leverage broadcasting: Write clean code that broadcasts instead of explicit tiling.
Use np.newaxis: Create proper dimensions for broadcasting.
Memory-mapped arrays: For large datasets, use np.memmap to avoid loading everything into memory.
Common Patterns
Pattern 1: Efficient Loop Replacement
# Instead of this:
result = []
for i in range(len(data)):
if data[i] > 0:
result.append(data[i] ** 2)
# Use this:
result = data[data > 0] ** 2
Pattern 2: Moving Average Calculation
def moving_average(arr, window):
"""Calculate moving average using convolution."""
kernel = np.ones(window) / window
return np.convolve(arr, kernel, mode='valid')
# Or using rolling window:
def rolling_mean(arr, window):
return np.array([arr[max(0,i):i+1].mean()
for i in range(len(arr))])
Pattern 3: Distance Matrix Computation
def compute_distance_matrix(X, metric='euclidean'):
"""Compute pairwise distances efficiently."""
# euclidean: ||a - b||^2 = ||a||^2 + ||b||^2 - 2*a.b
X_sq = np.sum(X**2, axis=1)
dist_sq = X_sq[:, np.newaxis] + X_sq[np.newaxis, :] - 2 @ X @ X.T
dist_sq = np.maximum(dist_sq, 0) # Numerical precision
if metric == 'euclidean':
return np.sqrt(dist_sq)
return dist_sq
1---2name: numpy3description: Numerical computing library providing support for large, multi-dimensional arrays, mathematical functions, linear algebra, random number generation, and Fourier transforms.4---56# NumPy78## What I do910I provide fundamental numerical computing capabilities for Python through powerful N-dimensional array objects and mathematical functions. I enable efficient array operations, linear algebra computations, random number generation, Fourier transforms, and statistical calculations. I am the backbone of scientific computing in Python and serve as the foundation for pandas, scikit-learn, and other data science libraries.1112## When to use me1314- Performing numerical computations on large datasets15- Working with multi-dimensional arrays and matrices16- Implementing mathematical and statistical operations17- Linear algebra operations (matrix multiplication, eigenvalues, decompositions)18- Random sampling and probability distributions19- Signal processing and Fourier analysis20- Image processing (as multi-dimensional arrays)21- Performance-critical numerical code2223## Core Concepts2425### Arrays26- **ndarray**: N-dimensional array object with homogeneous data types27- **Shape**: Dimensions of the array (e.g., (1000, 50) for 1000 rows, 50 columns)28- **Data Types**: int8-uint64, float16-float128, complex, bool, object29- **Memory Layout**: C-contiguous (row-major) or Fortran-contiguous (column-major)3031### Array Creation32- **From scratch**: `np.zeros()`, `np.ones()`, `np.empty()`, `np.arange()`, `np.linspace()`33- **From data**: `np.array()`, `np.asarray()`, `np.fromfunction()`34- **Random arrays**: `np.random.rand()`, `np.random.randint()`, `np.random.randn()`35- **Special matrices**: `np.eye()`, `np.identity()`, `np.diag()`3637### Indexing and Slicing38- **Basic indexing**: Single element `arr[0, 0]`, slices `arr[1:5, :]`39- **Boolean indexing**: `arr[arr > 0]` for filtering40- **Fancy indexing**: `arr[[0, 2, 5]]` for multiple indices41- **Advanced indexing**: Integer arrays `arr[np.newaxis, :]`4243### Broadcasting44- Automatic expansion of arrays with different shapes for element-wise operations45- Rule 1: Dimensions match from right to left46- Rule 2: Dimensions of size 1 can be stretched to match47- Enables vectorized operations without explicit loops4849### Vectorization50- **ufuncs**: Universal functions for element-wise operations (np.add, np.multiply)51- **Reduction operations**: `np.sum()`, `np.mean()`, `np.max()`, `np.min()`52- **Accumulation**: `np.cumsum()`, `np.cumprod()`53- **Sorting**: `np.sort()`, `np.argsort()`, `np.partition()`5455## Code Examples (Python)5657```python58import numpy as np5960# Array creation61arr = np.array([1, 2, 3, 4, 5])62zeros = np.zeros((3, 4))63ones = np.ones((2, 3), dtype=int)64arange = np.arange(0, 10, 2)65linspace = np.linspace(0, 1, 100)66random = np.random.rand(1000)67random_normal = np.random.randn(1000)68random_int = np.random.randint(0, 100, (5, 5))69identity = np.eye(3)70diagonal = np.diag([1, 2, 3])7172# Array properties73arr.shape # (5,) or (rows, cols)74arr.dtype # dtype('int64')75arr.ndim # Number of dimensions76arr.size # Total elements77arr.nbytes # Memory usage in bytes7879# Reshaping80arr = np.arange(12)81reshaped = arr.reshape(3, 4)82flattened = reshaped.ravel()83transposed = reshaped.T84newaxis = arr[:, np.newaxis]8586# Indexing87arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])88arr[0, 0] # First element: 189arr[0] # First row: [1, 2, 3]90arr[:, 0] # First column: [1, 4, 7]91arr[1:3, 1:3] # Sub-array92arr[arr > 5] # Boolean indexing: [6, 7, 8, 9]93arr[[0, 2], [0, 2]] # Fancy indexing: [1, 9]9495# Mathematical operations96arr1 = np.array([1, 2, 3])97arr2 = np.array([4, 5, 6])98np.add(arr1, arr2) # [5, 7, 9]99np.multiply(arr1, arr2) # [4, 10, 18]100np.divide(arr1, arr2) # [0.25, 0.4, 0.5]101np.power(arr1, 2) # [1, 4, 9]102np.sqrt(arr1) # [1.0, 1.414, 1.732]103np.exp(arr1) # [2.718, 7.389, 20.086]104np.log(arr1) # [0.0, 0.693, 1.099]105106# Broadcasting107arr1 = np.array([[1], [2], [3]]) # (3, 1)108arr2 = np.array([4, 5, 6]) # (3,)109result = arr1 + arr2 # [[5, 6, 7], [6, 7, 8], [7, 8, 9]]110111# Reductions112arr = np.array([1, 2, 3, 4, 5])113np.sum(arr) # 15114np.mean(arr) # 3.0115np.std(arr) # 1.414...116np.var(arr) # 2.0117np.min(arr) # 1118np.max(arr) # 5119np.argmax(arr) # 4120np.median(arr) # 3.0121np.percentile(arr, 75) # 4.0122123# Axis-based operations124matrix = np.array([[1, 2, 3], [4, 5, 6]])125np.sum(matrix, axis=0) # Column sums: [5, 7, 9]126np.sum(matrix, axis=1) # Row sums: [6, 15]127np.mean(matrix, axis=1) # Row means: [2.0, 5.0]128129# Linear algebra130A = np.array([[1, 2], [3, 4]])131B = np.array([[5, 6], [7, 8]])132np.dot(A, B) # Matrix multiplication133A @ B # Same as above134np.linalg.det(A) # Determinant: -2135np.linalg.inv(A) # Inverse136np.linalg.eig(A) # Eigenvalues and eigenvectors137np.linalg.solve(A, np.array([5, 6])) # Solve Ax = b138np.linalg.svd(A) # Singular value decomposition139np.linalg.qr(A) # QR decomposition140np.linalg.norm(A) # Matrix/vector norm141142# Random number generation143np.random.seed(42) # Set seed144np.random.rand(5) # Uniform [0, 1)145np.random.randn(5) # Standard normal146np.random.randint(0, 10, 5) # Random integers147np.random.uniform(0, 1, 5) # Explicit uniform148np.random.normal(0, 1, 5) # Explicit normal149np.random.choice([1, 2, 3, 4, 5], 3, replace=False) # Without replacement150np.random.permutation(5) # Permutation151152# Distributions153np.random.binomial(10, 0.5, 100) # Binomial154np.random.poisson(5, 100) # Poisson155np.random.exponential(1, 100) # Exponential156np.random.uniform(0, 1, 100) # Uniform157np.random.normal(0, 1, 100) # Normal158159# Sorting160arr = np.array([3, 1, 4, 1, 5, 9, 2])161np.sort(arr) # Sorted array162np.argsort(arr) # Indices163np.partition(arr, 3) # Partition around 3rd element164165# Set operations166arr1 = np.array([1, 2, 3, 4, 5])167arr2 = np.array([3, 4, 5, 6, 7])168np.union1d(arr1, arr2) # [1, 2, 3, 4, 5, 6, 7]169np.intersect1d(arr1, arr2) # [3, 4, 5]170np.setdiff1d(arr1, arr2) # [1, 2]171```172173## Best Practices1741751. **Use vectorization**: Replace Python loops with NumPy vectorized operations for 10-100x speedup.1761772. **Pre-allocate arrays**: Create arrays with known sizes before loops instead of appending.1781793. **Use appropriate dtypes**: Choose smaller dtypes (float32 instead of float64) when precision permits.1801814. **Avoid copies**: Use views (`reshape`, `strides`) instead of copies when possible.1821835. **Use in-place operations**: `arr += 5` instead of `arr = arr + 5` to avoid temporary arrays.1841856. **Leverage broadcasting**: Write clean code that broadcasts instead of explicit tiling.1861877. **Use np.newaxis**: Create proper dimensions for broadcasting.1881898. **Memory-mapped arrays**: For large datasets, use `np.memmap` to avoid loading everything into memory.190191## Common Patterns192193### Pattern 1: Efficient Loop Replacement194```python195# Instead of this:196result = []197for i in range(len(data)):198 if data[i] > 0:199 result.append(data[i] ** 2)200201# Use this:202result = data[data > 0] ** 2203```204205### Pattern 2: Moving Average Calculation206```python207def moving_average(arr, window):208 """Calculate moving average using convolution."""209 kernel = np.ones(window) / window210 return np.convolve(arr, kernel, mode='valid')211212# Or using rolling window:213def rolling_mean(arr, window):214 return np.array([arr[max(0,i):i+1].mean() 215 for i in range(len(arr))])216```217218### Pattern 3: Distance Matrix Computation219```python220def compute_distance_matrix(X, metric='euclidean'):221 """Compute pairwise distances efficiently."""222 # euclidean: ||a - b||^2 = ||a||^2 + ||b||^2 - 2*a.b223 X_sq = np.sum(X**2, axis=1)224 dist_sq = X_sq[:, np.newaxis] + X_sq[np.newaxis, :] - 2 @ X @ X.T225 dist_sq = np.maximum(dist_sq, 0) # Numerical precision226 if metric == 'euclidean':227 return np.sqrt(dist_sq)228 return dist_sq229```