mirror of
https://github.com/Rainyy21/framework_note.git
synced 2026-10-11 00:30:29 -04:00
vault backup: 2026-05-30 16:02:33
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
---
|
||||
title: Introduction to NumPy
|
||||
tags:
|
||||
- python
|
||||
- numpy
|
||||
- data-science
|
||||
- numerical-computing
|
||||
category: Lesson
|
||||
difficulty: Beginner to Intermediate
|
||||
created: 2026-05-26
|
||||
---
|
||||
|
||||
# Introduction to NumPy
|
||||
|
||||
> [!abstract] What is NumPy?
|
||||
> **NumPy** (Numerical Python) is the foundational library for scientific computing in Python. It provides a high-performance multidimensional array object, tools for working with these arrays, and linear algebra, Fourier transform, and random number capabilities.
|
||||
>
|
||||
> ### Why use NumPy instead of standard Python lists?
|
||||
> 1. **Speed:** NumPy arrays are written in C, making mathematical operations up to 100x faster than standard Python lists.
|
||||
> 2. **Memory Efficiency:** NumPy arrays use contiguous blocks of memory, whereas Python lists store pointers to objects scattered across memory.
|
||||
> 3. **Vectorization:** It allows performing mathematical operations on whole arrays without writing slow `for` loops.
|
||||
|
||||
---
|
||||
|
||||
## 📐 The N-Dimensional Array (`ndarray`)
|
||||
|
||||
The core of NumPy is the **`ndarray`** (N-dimensional array). It is a grid of values, all of the **same type** (homogenous), indexed by a tuple of non-negative integers.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[ndarray] --> B["1D Array (Vector) <br> Shape: (n,)"]
|
||||
A --> C["2D Array (Matrix) <br> Shape: (m, n)"]
|
||||
A --> D["3D Array (Tensor) <br> Shape: (p, m, n)"]
|
||||
```
|
||||
|
||||
### Essential Array Attributes
|
||||
Every array has attributes that describe its structure:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
arr = np.array([[1, 2, 3], [4, 5, 6]])
|
||||
|
||||
print(arr.ndim) # Number of dimensions (axes) -> 2
|
||||
print(arr.shape) # Tuple representing sizes in each dimension -> (2, 3)
|
||||
print(arr.size) # Total number of elements -> 6
|
||||
print(arr.dtype) # Data type of the elements -> int64
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Creating Arrays
|
||||
|
||||
First, import the library using the standard alias:
|
||||
```python
|
||||
import numpy as np
|
||||
```
|
||||
|
||||
### 1. From Python Lists
|
||||
```python
|
||||
# 1D Vector
|
||||
v = np.array([1, 2, 3])
|
||||
|
||||
# 2D Matrix
|
||||
m = np.array([[1, 2], [3, 4]])
|
||||
```
|
||||
|
||||
### 2. Built-in Placeholders
|
||||
NumPy provides functions to initialize arrays with placeholders, avoiding manual creation:
|
||||
|
||||
```python
|
||||
# Array of zeros
|
||||
zeros = np.zeros((3, 4)) # 3 rows, 4 columns
|
||||
|
||||
# Array of ones
|
||||
ones = np.ones((2, 3), dtype=np.int32)
|
||||
|
||||
# Range of numbers (similar to range())
|
||||
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
|
||||
|
||||
# Linearly spaced numbers
|
||||
linspace_arr = np.linspace(0, 1, 5) # [0.0, 0.25, 0.5, 0.75, 1.0]
|
||||
|
||||
# Identity Matrix
|
||||
eye_matrix = np.eye(3) # 3x3 identity matrix
|
||||
```
|
||||
|
||||
### 3. Random Number Generation
|
||||
```python
|
||||
# Uniform random values between [0.0, 1.0)
|
||||
rand_arr = np.random.rand(2, 2)
|
||||
|
||||
# Standard normal distribution (mean=0, std=1)
|
||||
randn_arr = np.random.randn(2, 2)
|
||||
|
||||
# Random integers
|
||||
rand_ints = np.random.randint(1, 100, size=(5,))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Element-wise Operations & Vectorization
|
||||
|
||||
In standard Python, to add two lists element-wise, you need a list comprehension or loop. In NumPy, you do it directly.
|
||||
|
||||
```python
|
||||
x = np.array([1, 2, 3])
|
||||
y = np.array([4, 5, 6])
|
||||
|
||||
print(x + y) # [5, 7, 9]
|
||||
print(x * y) # [4, 10, 18]
|
||||
print(x ** 2) # [1, 4, 9]
|
||||
```
|
||||
|
||||
### 📡 Broadcasting
|
||||
Broadcasting is a powerful mechanism that allows NumPy to perform arithmetic operations on arrays of **different shapes**. The smaller array is "broadcast" across the larger array so that they have compatible shapes.
|
||||
|
||||
```python
|
||||
matrix = np.array([[1, 2, 3], [4, 5, 6]])
|
||||
scalar = 10
|
||||
|
||||
# The scalar is added to every single element
|
||||
print(matrix + scalar)
|
||||
# [[11, 12, 13]
|
||||
# [14, 15, 16]]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Indexing, Slicing & Masking
|
||||
|
||||
### Slicing 2D Arrays
|
||||
Slicing follows the format `array[row_start:row_end, col_start:col_end]`.
|
||||
|
||||
```python
|
||||
arr = np.array([
|
||||
[10, 11, 12],
|
||||
[20, 21, 22],
|
||||
[30, 31, 32]
|
||||
])
|
||||
|
||||
# Get row at index 1
|
||||
print(arr[1, :]) # [20, 21, 22]
|
||||
|
||||
# Get column at index 2
|
||||
print(arr[:, 2]) # [12, 22, 32]
|
||||
|
||||
# Slice a subgrid (top-left 2x2)
|
||||
print(arr[0:2, 0:2])
|
||||
# [[10, 11]
|
||||
# [20, 21]]
|
||||
```
|
||||
|
||||
### 🎭 Boolean Masking (Conditional Filtering)
|
||||
You can filter arrays using conditions. NumPy returns elements where the condition resolves to `True`.
|
||||
|
||||
```python
|
||||
data = np.array([1, 5, 8, 12, 3, 15])
|
||||
|
||||
# Create a boolean mask
|
||||
mask = data > 5 # [False, False, True, True, False, True]
|
||||
|
||||
# Filter using the mask
|
||||
filtered_data = data[mask] # [8, 12, 15]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧮 Common Aggregations & Axis Operations
|
||||
|
||||
Aggregations allow you to compute statistics over entire arrays or along specific **axes**:
|
||||
* `axis=0`: Down the columns (collapses rows).
|
||||
* `axis=1`: Across the rows (collapses columns).
|
||||
|
||||
```python
|
||||
arr = np.array([[1, 2], [3, 4]])
|
||||
|
||||
# Sum of all elements
|
||||
print(np.sum(arr)) # 10
|
||||
|
||||
# Sum down the columns (vertical)
|
||||
print(np.sum(arr, axis=0)) # [4, 6]
|
||||
|
||||
# Sum across the rows (horizontal)
|
||||
print(np.sum(arr, axis=1)) # [3, 7]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Reshaping and Transposing
|
||||
|
||||
You can change the shape of an array without changing its data using `.reshape()` or `.T` (Transpose).
|
||||
|
||||
```python
|
||||
flat = np.arange(1, 7) # [1, 2, 3, 4, 5, 6]
|
||||
|
||||
# Reshape into a 2x3 matrix
|
||||
matrix = flat.reshape(2, 3)
|
||||
# [[1, 2, 3]
|
||||
# [4, 5, 6]]
|
||||
|
||||
# Transpose matrix (swap rows and columns)
|
||||
transposed = matrix.T
|
||||
# [[1, 4]
|
||||
# [2, 5]
|
||||
# [3, 6]]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
> [!important] Avoid Standard Loops
|
||||
> Standard loops in Python are interpreted, which adds massive overhead. Vectorized operations execute in compiled C, taking advantage of CPU caches and SIMD instructions.
|
||||
>
|
||||
> **Example Comparison:**
|
||||
> ```python
|
||||
> # ❌ Extremely Slow
|
||||
> values = np.random.rand(1_000_000)
|
||||
> reciprocal = [1 / x for x in values]
|
||||
>
|
||||
> # ✅ Near Instantaneous
|
||||
> reciprocal = 1 / values
|
||||
> ```
|
||||
|
||||
> [!tip] Use In-place Operations to Save Memory
|
||||
> Instead of creating a new copy, perform calculations directly on the existing array if possible using syntax like `+=`, `-=`, or `*=`.
|
||||
> ```python
|
||||
> a = np.ones(1000000)
|
||||
> b = np.ones(1000000)
|
||||
>
|
||||
> # Allocates new memory
|
||||
> a = a + b
|
||||
>
|
||||
> # Modifies 'a' in-place (saves memory allocation time)
|
||||
> a += b
|
||||
> ```
|
||||
Reference in New Issue
Block a user