1. NumPy Basics
1. NumPy Basics¶
Overview¶
NumPy (Numerical Python) is the core library for numerical computing in Python. It provides multidimensional array objects and various functions for array operations.
1. Creating NumPy Arrays¶
1.1 Basic Array Creation¶
import numpy as np
# Creating array from list
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # [1 2 3 4 5]
print(type(arr1)) # <class 'numpy.ndarray'>
# 2D array
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
# [4 5 6]]
# 3D array
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(arr3.shape) # (2, 2, 2)
1.2 Creating Special Arrays¶
# Array filled with zeros
zeros = np.zeros((3, 4))
print(zeros)
# Array filled with ones
ones = np.ones((2, 3))
print(ones)
# Array filled with specific value
full = np.full((2, 2), 7)
print(full) # [[7 7], [7 7]]
# Identity matrix
eye = np.eye(3)
print(eye)
# Empty array (uninitialized values)
empty = np.empty((2, 3))
1.3 Creating Sequential Arrays¶
# arange: range specification
arr = np.arange(0, 10, 2) # From 0 to less than 10, step 2
print(arr) # [0 2 4 6 8]
# linspace: evenly spaced division
arr = np.linspace(0, 1, 5) # 0 to 1 divided into 5 equal parts
print(arr) # [0. 0.25 0.5 0.75 1. ]
# logspace: logarithmic scale spacing
arr = np.logspace(0, 2, 5) # 10^0 to 10^2
print(arr) # [ 1. 3.16 10. 31.62 100. ]
2. Array Attributes¶
arr = np.array([[1, 2, 3], [4, 5, 6]])
# Number of dimensions
print(arr.ndim) # 2
# Shape
print(arr.shape) # (2, 3)
# Total number of elements
print(arr.size) # 6
# Data type
print(arr.dtype) # int64
# Bytes per element
print(arr.itemsize) # 8
# Total bytes
print(arr.nbytes) # 48
Data Type Specification¶
# Integer
arr_int = np.array([1, 2, 3], dtype=np.int32)
# Float
arr_float = np.array([1, 2, 3], dtype=np.float64)
# Complex
arr_complex = np.array([1, 2, 3], dtype=np.complex128)
# Boolean
arr_bool = np.array([0, 1, 0, 1], dtype=np.bool_)
# Type conversion
arr = np.array([1.5, 2.7, 3.9])
arr_int = arr.astype(np.int32) # [1, 2, 3]
3. Indexing and Slicing¶
3.1 Basic Indexing¶
arr = np.array([10, 20, 30, 40, 50])
# Single element access
print(arr[0]) # 10
print(arr[-1]) # 50
# 2D array
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0, 0]) # 1
print(arr2d[1, 2]) # 6
print(arr2d[-1, -1]) # 9
3.2 Slicing¶
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Basic slicing [start:stop:step]
print(arr[2:7]) # [2 3 4 5 6]
print(arr[::2]) # [0 2 4 6 8]
print(arr[::-1]) # [9 8 7 6 5 4 3 2 1 0]
# 2D slicing
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0:2, 1:3])
# [[2 3]
# [5 6]]
print(arr2d[:, 0]) # First column: [1 4 7]
print(arr2d[1, :]) # Second row: [4 5 6]
3.3 Boolean Indexing¶
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# Select elements satisfying condition
mask = arr > 5
print(mask) # [False False False False False True True True True True]
print(arr[mask]) # [ 6 7 8 9 10]
# Direct condition use
print(arr[arr > 5]) # [ 6 7 8 9 10]
print(arr[arr % 2 == 0]) # [ 2 4 6 8 10]
# Compound conditions
print(arr[(arr > 3) & (arr < 8)]) # [4 5 6 7]
print(arr[(arr < 3) | (arr > 8)]) # [ 1 2 9 10]
3.4 Fancy Indexing¶
arr = np.array([10, 20, 30, 40, 50])
# Access by index array
indices = [0, 2, 4]
print(arr[indices]) # [10 30 50]
# 2D array
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Select specific rows
print(arr2d[[0, 2]])
# [[1 2 3]
# [7 8 9]]
# Select specific elements
rows = [0, 1, 2]
cols = [0, 1, 2]
print(arr2d[rows, cols]) # [1 5 9] (diagonal elements)
4. Reshaping Arrays¶
4.1 reshape¶
arr = np.arange(12)
print(arr) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
# Convert to 2D
arr2d = arr.reshape(3, 4)
print(arr2d)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# Using -1: automatic calculation
arr2d = arr.reshape(4, -1) # 4 rows, columns auto-calculated
print(arr2d.shape) # (4, 3)
arr2d = arr.reshape(-1, 6) # Rows auto-calculated, 6 columns
print(arr2d.shape) # (2, 6)
4.2 flatten and ravel¶
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
# flatten: creates copy
flat = arr2d.flatten()
print(flat) # [1 2 3 4 5 6]
# ravel: creates view (shares original)
rav = arr2d.ravel()
print(rav) # [1 2 3 4 5 6]
4.3 Transpose¶
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3)
# Transpose
transposed = arr.T
print(transposed)
# [[1 4]
# [2 5]
# [3 6]]
print(transposed.shape) # (3, 2)
# Multidimensional transpose
arr3d = np.arange(24).reshape(2, 3, 4)
print(arr3d.transpose(1, 0, 2).shape) # (3, 2, 4)
4.4 Adding/Removing Dimensions¶
arr = np.array([1, 2, 3])
print(arr.shape) # (3,)
# Add dimension
arr_2d = arr[np.newaxis, :] # or arr.reshape(1, -1)
print(arr_2d.shape) # (1, 3)
arr_col = arr[:, np.newaxis] # or arr.reshape(-1, 1)
print(arr_col.shape) # (3, 1)
# Using expand_dims
arr_exp = np.expand_dims(arr, axis=0)
print(arr_exp.shape) # (1, 3)
# squeeze: remove dimensions of size 1
arr = np.array([[[1, 2, 3]]])
print(arr.shape) # (1, 1, 3)
print(np.squeeze(arr).shape) # (3,)
5. Array Operations¶
5.1 Basic Arithmetic Operations¶
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# Element-wise operations
print(a + b) # [11 22 33 44]
print(a - b) # [ -9 -18 -27 -36]
print(a * b) # [ 10 40 90 160]
print(a / b) # [0.1 0.1 0.1 0.1]
print(a ** 2) # [ 1 4 9 16]
print(a % 2) # [1 0 1 0]
print(a // 2) # [0 1 1 2]
# Scalar operations
print(a + 10) # [11 12 13 14]
print(a * 2) # [2 4 6 8]
5.2 Universal Functions (ufuncs)¶
arr = np.array([1, 4, 9, 16, 25])
# Mathematical functions
print(np.sqrt(arr)) # [1. 2. 3. 4. 5.]
print(np.exp(arr)) # exponential
print(np.log(arr)) # natural logarithm
print(np.log10(arr)) # common logarithm
# Trigonometric functions
angles = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])
print(np.sin(angles))
print(np.cos(angles))
print(np.tan(angles))
# Rounding
arr = np.array([1.2, 2.5, 3.7, 4.4])
print(np.round(arr)) # [1. 2. 4. 4.]
print(np.floor(arr)) # [1. 2. 3. 4.]
print(np.ceil(arr)) # [2. 3. 4. 5.]
print(np.trunc(arr)) # [1. 2. 3. 4.]
# Absolute value
arr = np.array([-1, -2, 3, -4])
print(np.abs(arr)) # [1 2 3 4]
5.3 Aggregation Functions¶
arr = np.array([[1, 2, 3], [4, 5, 6]])
# Overall aggregation
print(np.sum(arr)) # 21
print(np.mean(arr)) # 3.5
print(np.std(arr)) # 1.707...
print(np.var(arr)) # 2.916...
print(np.min(arr)) # 1
print(np.max(arr)) # 6
print(np.prod(arr)) # 720 (product of all elements)
# Axis-based aggregation
print(np.sum(arr, axis=0)) # column sum: [5 7 9]
print(np.sum(arr, axis=1)) # row sum: [6 15]
print(np.mean(arr, axis=0)) # column mean: [2.5 3.5 4.5]
print(np.mean(arr, axis=1)) # row mean: [2. 5.]
# Cumulative sum/product
print(np.cumsum(arr)) # [ 1 3 6 10 15 21]
print(np.cumprod(arr)) # [ 1 2 6 24 120 720]
# Return indices
print(np.argmin(arr)) # 0 (index of minimum)
print(np.argmax(arr)) # 5 (index of maximum)
6. Broadcasting¶
Broadcasting is a core NumPy feature that enables operations between arrays of different sizes.
6.1 Broadcasting Rules¶
- If arrays have different number of dimensions, prepend 1s to the shape of the smaller array
- Arrays with size 1 in any dimension are stretched to match the size of the other array
- If sizes are not equal and neither is 1, an error occurs
# Scalar and array
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr + 10)
# [[11 12 13]
# [14 15 16]]
# 1D and 2D
arr = np.array([[1, 2, 3], [4, 5, 6]])
row = np.array([10, 20, 30])
print(arr + row)
# [[11 22 33]
# [14 25 36]]
# Column vector and 2D
col = np.array([[100], [200]])
print(arr + col)
# [[101 102 103]
# [204 205 206]]
6.2 Broadcasting Examples¶
# Standardization
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mean = np.mean(data, axis=0) # [4. 5. 6.]
std = np.std(data, axis=0) # [2.449 2.449 2.449]
standardized = (data - mean) / std
# Distance calculation
point = np.array([1, 2])
points = np.array([[0, 0], [1, 1], [2, 2], [3, 3]])
distances = np.sqrt(np.sum((points - point) ** 2, axis=1))
print(distances) # [2.236 1. 1.414 2.236]
7. Combining and Splitting Arrays¶
7.1 Combining Arrays¶
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# Vertical stacking (row direction)
v_stack = np.vstack([a, b])
print(v_stack)
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# Horizontal stacking (column direction)
h_stack = np.hstack([a, b])
print(h_stack)
# [[1 2 5 6]
# [3 4 7 8]]
# Using concatenate
concat_v = np.concatenate([a, b], axis=0) # same as vstack
concat_h = np.concatenate([a, b], axis=1) # same as hstack
# Depth stacking
d_stack = np.dstack([a, b])
print(d_stack.shape) # (2, 2, 2)
7.2 Splitting Arrays¶
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# Vertical split
v_split = np.vsplit(arr, 3) # split into 3
print(len(v_split)) # 3
# Horizontal split
h_split = np.hsplit(arr, 2) # split into 2
print(h_split[0])
# [[ 1 2]
# [ 5 6]
# [ 9 10]]
# Using split
split_arr = np.split(arr, [1, 2], axis=0) # split at indices 1, 2
print(len(split_arr)) # 3
8. Copying and Views¶
8.1 View - Shallow Copy¶
arr = np.array([1, 2, 3, 4, 5])
# Slicing creates a view
view = arr[1:4]
view[0] = 100
print(arr) # [ 1 100 3 4 5] # original also changed
print(view) # [100 3 4]
8.2 Copy - Deep Copy¶
arr = np.array([1, 2, 3, 4, 5])
# Explicit copy
copy = arr.copy()
copy[0] = 100
print(arr) # [1 2 3 4 5] # original preserved
print(copy) # [100 2 3 4 5]
Practice Problems¶
Problem 1: Array Creation¶
Create an array containing only multiples of 3 from 1 to 100.
# Solution
arr = np.arange(3, 101, 3)
# or
arr = np.arange(1, 101)
arr = arr[arr % 3 == 0]
Problem 2: Matrix Operations¶
Find the sum of diagonal elements of a 3x3 identity matrix.
# Solution
eye = np.eye(3)
diagonal_sum = np.trace(eye) # 3.0
# or
diagonal_sum = np.sum(np.diag(eye))
Problem 3: Broadcasting¶
Normalize a 4x4 matrix by dividing each element by the maximum value of its column.
# Solution
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]])
col_max = np.max(arr, axis=0) # [13, 14, 15, 16]
normalized = arr / col_max
Summary¶
| Feature | Functions/Methods |
|---|---|
| Array Creation | np.array(), np.zeros(), np.ones(), np.arange(), np.linspace() |
| Array Attributes | shape, dtype, ndim, size |
| Indexing | arr[i], arr[i, j], arr[condition], arr[indices] |
| Reshaping | reshape(), flatten(), ravel(), T |
| Operations | +, -, *, /, np.sum(), np.mean(), np.std() |
| Combining/Splitting | np.vstack(), np.hstack(), np.split() |