NumPy 入门:数组创建与基础操作

概述

NumPy 学习的第一课,从"为什么用 NumPy"出发,系统掌握数组创建的 6 种方法、数据类型选择、形状变换以及随机数生成入门。

学习目标

  • 理解 NumPy 相对 Python 原生列表的性能优势
  • 掌握 np.array(), np.arange(), np.linspace(), np.logspace() 等数组创建方法
  • 了解 dtype 对内存和精度的影响,学会选择合适的数据类型
  • 熟练使用 reshape(), .T, ravel() 进行形状变换
  • 使用现代 API (default_rng()) 生成随机数

核心内容 (7 个模块)

模块 核心知识点
1. 为什么用 NumPy 性能实测:比 Python 列表快约 22 倍
2. 数组创建 6 种方式:array / arange / linspace / logspace / zeros&ones / empty
3. 数据类型 dtype int8-64, uint8-64, float16/32/64;内存占用对比表
4. 形状变换 reshape(-1) 自动推导、flatten vs ravel、转置 .T
5. 随机数生成 default_rng()、均匀分布/正态分布/整数随机
6. 数组属性 shape / dtype / ndim / size / itemsize / nbytes
7. 总结回顾 知识要点 + 下一步预告
"""
=============================================================================
  NumPy 入门: 数组创建与基础操作
  (Learning Path - Step 1 of 10)
=============================================================================

本文件是 NumPy 学习的第一课,涵盖:
  1. 为什么选择 NumPy? (vs Python 列表)
  2. 数组的多种创建方式
  3. 数据类型 (dtype) 深入理解
  4. 数组形状变换 (reshape)
  5. 特殊数组生成
  6. 随机数生成入门

运行方式: python numpy/01_arrayBasics.py
=============================================================================
"""

import numpy as np


def section(title):
    """打印分隔标题"""
    print(f"\n{'='*60}")
    print(f"  {title}")
    print('='*60)


# =============================================================================
# 一、为什么用 NumPy? —— NumPy vs Python 列表性能对比
# =============================================================================

section("1. Why NumPy? -- Performance Comparison")

# 场景: 对 100万个元素求平方和
SIZE = 1_000_000

import time

# Python 原生列表
py_list = list(range(SIZE))
start = time.perf_counter()
sum_sq = sum(x * x for x in py_list)
py_time = time.perf_counter() - start
print(f"Python list:   {sum_sq:>20}  ({py_time:.4f}s)")

# NumPy 数组
np_arr = np.arange(SIZE, dtype=np.int64)
start = time.perf_counter()
sum_sq_np = np.sum(np_arr * np_arr)
np_time = time.perf_counter() - start
print(f"NumPy ndarray: {sum_sq_np:>20}  ({np_time:.4f}s)")
print(f"\nSpeedup: NumPy is ~{py_time/np_time:.0f}x faster!")
print(f"  Reason: NumPy uses contiguous memory + vectorized C operations")


# =============================================================================
# 二、数组创建方式大全
# =============================================================================

section("2. Array Creation Methods")

# --- 方法1: np.array() 从列表创建 ---
print("\n[Method 1] np.array() -- from Python list/tuple")

arr_1d = np.array([1, 2, 3, 4, 5])
print(f"  1D array from list: {arr_1d}, shape={arr_1d.shape}, dtype={arr_1d.dtype}")

arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(f"  2D array from nested lists:\n{arr_2d}")
print(f"  shape={arr_2d.shape} (2 rows, 3 cols), dtype={arr_2d.dtype}")

# 指定数据类型
arr_float = np.array([1, 2, 3], dtype=np.float32)
print(f"  With dtype=float32: {arr_float}, dtype={arr_float.dtype}")


# --- 方法2: np.arange() -- 等差序列 (类似 range()) ---
print("\n[Method 2] np.arange() -- evenly spaced values (like range())")

a = np.arange(10)                # 0..9, step=1
b = np.arange(2, 10)             # 2..9
c = np.arange(0, 1, 0.2)        # 0.0, 0.2, 0.4, 0.6, 0.8  (支持浮点步长!)
print(f"  arange(10):       {a}")
print(f"  arange(2,10):     {b}")
print(f"  arange(0,1,0.2):  {c}")
print("  Note: Unlike range(), arange() supports float step!")


# --- 方法3: np.linspace() -- 线性等分 ---
print("\n[Method 3] np.linspace() -- N evenly spaced numbers in [start, end]")

d = np.linspace(0, 9, 10)        # [0..9] 分成10份 (包含两端)
e = np.linspace(0, 1, 5)         # [0, 0.25, 0.5, 0.75, 1]
print(f"  linspace(0,9,10):  {d}")
print(f"  linspace(0,1,5):   {e}")
print("  Key diff from arange(): you specify NUMBER of points, not STEP")


# --- 方法4: np.logspace() / np.geomspace() ---
print("\n[Method 4] np.logspace() -- logarithmically spaced values")

f = np.logspace(0, 3, 4, base=10)  # 10^0, 10^1, 10^2, 10^3 = [1, 10, 100, 1000]
g = np.logspace(0, 10, 11, base=2) # 2^0, 2^1, ..., 2^10
print(f"  logspace(0,3,4,base=10): {f}")
print(f"  logspace(0,10,11,base=2):\n  {g}")
print("  Useful for: frequency ranges, exponential growth models")


# --- 方法5: 全零/全一/单位矩阵 ---
print("\n[Method 5] Special arrays -- zeros, ones, eye, full")

zeros_arr = np.zeros((2, 3))
ones_arr = np.ones((3, 2), dtype=np.int32)
eye_arr = np.eye(3)               # Identity matrix I_3x3
full_arr = np.full((2, 2), 7)     # All elements = 7

print(f"  zeros((2,3)):\n{zeros_arr}")
print(f"  ones((3,2), int32):\n{ones_arr}")
print(f"  eye(3) -- identity matrix:\n{eye_arr}")
print(f"  full((2,2), 7):\n{full_arr}")


# --- 方法6: 未初始化数组 (empty) ---
print("\n[Method 6] np.empty() -- uninitialized (faster than zeros)")

empty_arr = np.empty((2, 3))
print(f"  empty((2,3)) -- contains garbage values:\n{empty_arr}")
print("  Use case: when you will fill all values later anyway")


# =============================================================================
# 三、数据类型 (dtype) 深入理解
# =============================================================================

section("3. Data Types (dtype) -- Memory & Precision")

print("""
  NumPy supports rich data types beyond basic Python types:

  Type Prefix | Description          | Example Values
  ----------- | -------------------- | ------------------
  int8/16/32/64  | Signed integer     | -128 to 127 (int8)
  uint8/16/32/64 | Unsigned integer   | 0 to 255 (uint8)
  float16/32/64  | Floating point     | ~7 digits (float32)
  complex64/128  | Complex number     | a + bj
  bool            | Boolean           | True/False

  Rule of thumb:
    - Image data: use uint8 (0-255 per channel)
    - ML weights: use float32 (good precision/speed balance)
    - Scientific calc: use float64 (max precision)
""")

# 实际演示: 不同类型占用的内存差异
arr_i8 = np.zeros(10000, dtype=np.int8)
arr_i64 = np.zeros(10000, dtype=np.int64)
arr_f32 = np.zeros(10000, dtype=np.float32)
arr_f64 = np.zeros(10000, dtype=np.float64)

print(f"  Memory usage for 10,000 elements:")
print(f"    int8:    {arr_i8.nbytes:>6} bytes  (1 byte/element)")
print(f"    int64:   {arr_i64.nbytes:>6} bytes  (8 bytes/element)")
print(f"    float32: {arr_f32.nbytes:>6} bytes  (4 bytes/element)")
print(f"    float64: {arr_f64.nbytes:>6} bytes  (8 bytes/element)")
print(f"\n  Tip: Choosing the right dtype can save 2-8x memory!")


# 类型转换
print("\n  Type casting with .astype():")
arr_int = np.array([1, 2, 3])
arr_casted = arr_int.astype(np.float64)
print(f"    Original: {arr_int}, dtype={arr_int.dtype}")
print(f"    Casted:   {arr_casted}, dtype={arr_casted.dtype}")


# =============================================================================
# 四、数组形状变换 (reshape)
# =============================================================================

section("4. Shape Manipulation -- reshape, ravel, transpose")

# 创建一个 12 元素的一维数组
base = np.arange(12)
print(f"  Base array (12 elements): {base}\n")

# reshape 成不同形状
mat_3x4 = base.reshape(3, 4)
mat_2x6 = base.reshape(2, 6)
mat_2x2x3 = base.reshape(2, 2, 3)

print(f"  Reshape to (3,4):\n{mat_3x4}")
print(f"  shape={mat_3x4.shape}, ndim={mat_3x4.ndim} (dimensions)\n")

print(f"  Reshape to (2,6):\n{mat_2x6}\n")

print(f"  Reshape to (2,2,3) -- 3D tensor:\n{mat_2x2x3}")
print(f"  ndim={mat_2x2x3.ndim} (this is a rank-3 tensor)\n")


# flatten vs ravel
print("  Flatten vs Ravel:")
flat_copy = mat_3x4.flatten()   # Returns a COPY
flat_view = mat_3x4.ravel()      # Returns a VIEW (no memory copy)
print(f"    flatten(): returns copy, id={id(flat_copy)}")
print(f"    ravel():   returns view, id={id(flat_view)}")
print(f"    They look same: {np.array_equal(flat_copy, flat_view)}")


# Transpose (.T)
print(f"\n  Transpose of (3,4) -> (4,3):\n{mat_3x4.T}")
print(f"  Original shape: {mat_3x4.shape} -> Transposed: {mat_3x4.T.shape}")


# 使用 -1 自动推导维度 (非常实用!)
auto_shape = base.reshape(3, -1)   # -1 means "figure it out"
print(f"\n  reshape(3, -1): auto-computes columns -> shape={auto_shape.shape}")
print(f"  reshape(-1, 4): auto-computes rows -> shape={base.reshape(-1, 4).shape}")


# =============================================================================
# 五、随机数生成入门
# =============================================================================

section("5. Random Number Generation -- The Modern Way")

# NumPy >= 1.17 推荐使用 Generator API (比旧的 np.random 更好)
rng = np.random.default_rng(seed=42)  # 设置种子以保证可复现

print("  Using default_rng() -- modern recommended API:")

# 均匀分布 [0, 1)
uniform = rng.random(5)
print(f"    Uniform [0,1): {uniform}")

# 标准正态分布 N(0,1)
normal = rng.standard_normal(5)
print(f"    Normal N(0,1): {normal.round(3)}")

# 整数随机 [low, high)
integers = rng.integers(0, 100, size=5)
print(f"    Integers [0,99]: {integers}")

# 从给定选项中随机选择
choices = rng.choice(['apple', 'banana', 'cherry'], size=5, p=[0.5, 0.3, 0.2])
print(f"    Weighted choice: {choices}")

# 打乱数组顺序
arr_shuffle = np.arange(10)
rng.shuffle(arr_shuffle)  # In-place shuffle
print(f"    Shuffle 0-9:   {arr_shuffle}")


# =============================================================================
# 六、数组属性速查
# =============================================================================

section("6. Array Attributes -- Quick Reference")

demo = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)

attributes = {
    'ndim': f"{demo.ndim} (number of dimensions/axes)",
    'shape': f"{demo.shape} (size of each dimension)",
    'size': f"{demo.size} (total element count)",
    'dtype': f"{demo.dtype} (data type of each element)",
    'itemsize': f"{demo.itemsize} (bytes per element)",
    'nbytes': f"{demo.nbytes} (total memory usage)",
}

for attr, desc in attributes.items():
    value = getattr(demo, attr)
    print(f"  arr.{attr:<10} = {str(value):<30} # {desc}")


# =============================================================================
# 七、总结与下一步
# =============================================================================

section("7. Summary & Next Steps")

summary = r"""
+----------------------------------------------------------+
|  What You Learned Today                                  |
+----------------------------------------------------------+
|                                                          |
|  1. NumPy is 10-100x faster than Python lists            |
|  2. Array creation: array, arange, linspace, logspace    |
|  3. Special arrays: zeros, ones, eye, full, empty        |
|  4. Data types matter for memory and precision           |
|  5. reshape(-1) auto-infers dimensions                   |
|  6. Use default_rng() for random numbers                 |
|  7. Core attributes: shape, dtype, ndim, size            |
|                                                          |
+----------------------------------------------------------+
|  Next: 02_arrayIndexing.py                               |
|  You will learn: slicing, fancy indexing, boolean masks   |
+----------------------------------------------------------+
"""

print(summary)

print("\nAll done! Ready for Step 2: Array Indexing.\n")

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐