🔢 NumPy

从零开始的数据分析之旅

📖 NumPy核心概念

NumPy是Python科学计算的基石。它的核心是ndarray(N-dimensional array)——一个高效的多维数组对象,支持向量化运算、广播机制和丰富的数学函数。掌握NumPy是学习Pandas、Scikit-learn等库的前提。

NumPy知识体系: 数组创建 数组运算 线性代数 ──────── ──────── ────────── np.array() 算术运算 np.linalg np.zeros/ones() ├ 加减乘除 ├ det() 行列式 np.arange() ├ 幂运算 ├ inv() 逆矩阵 np.linspace() └ 比较运算 ├ eig() 特征值 np.random 矩阵运算 ├ solve() 线性方程 ├ dot() / @ └ norm() 范数 形状操作 ├ matmul() ──────── └ 转置 .T 统计函数 reshape() ──────── flatten() 广播机制 mean/std/var transpose() ──────── sum/cumsum squeeze() 规则1: 维度对齐 min/max expand_dims() 规则2: 1可扩展 argmin/argmax 规则3: 不匹配报错

1. 多维数组创建

import numpy as np

# 基本创建
a = np.array([1, 2, 3, 4, 5])
b = np.zeros((3, 4))        # 3×4零矩阵
c = np.ones((2, 3))          # 2×3全1矩阵
d = np.arange(0, 10, 2)      # [0, 2, 4, 6, 8]
e = np.linspace(0, 1, 5)     # [0, 0.25, 0.5, 0.75, 1.0]

# 随机数组
np.random.seed(42)
r1 = np.random.rand(3, 3)    # 均匀分布 [0, 1)
r2 = np.random.randn(3, 3)   # 标准正态分布
r3 = np.random.randint(0, 10, (3, 3))  # 整数 [0, 10)

🧮 矩阵运算与线性代数

矩阵乘法

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 三种矩阵乘法写法
C1 = A @ B           # Python 3.5+ 推荐写法
C2 = A.dot(B)        # 方法调用
C3 = np.matmul(A, B) # 函数调用
# 结果: [[19 22], [43 50]]

# 行列式和逆矩阵
print(f"行列式: {np.linalg.det(A):.1f}")    # -2.0
print(f"逆矩阵:\n{np.linalg.inv(A).round(2)}")  # [[-2.  1.], [1.5 -0.5]]

# 特征值与特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print(f"特征值: {eigenvalues.round(2)}")  # [-0.37  5.37]

线性方程组求解

Ax = b → x = A⁻¹b
# 解方程组: 2x + y = 5, x + 3y = 10
A = np.array([[2, 1], [1, 3]])
b = np.array([5, 10])
x = np.linalg.solve(A, b)
print(f"x={x[0]:.2f}, y={x[1]:.2f}")  # x=1.0, y=3.0

📡 广播机制详解

广播是NumPy最强大的特性之一,允许不同形状的数组进行运算,无需显式复制数据。

广播三规则:
① 维度从末尾开始对齐
② 维度大小为1时,沿该维度扩展
③ 维度大小不匹配且都不为1时,报错
# 广播示例
row = np.array([[1, 2, 3]])    # 1×3
col = np.array([[10], [20]])   # 2×1
result = row + col              # 2×3

# 结果:
# [[11 12 13],
#  [21 22 23]]

# 标准化每一列
data = np.random.randn(100, 5)  # 100×5
mean = data.mean(axis=0)         # 1×5
std = data.std(axis=0)           # 1×5
normalized = (data - mean) / std  # 广播: (100×5) - (1×5)
广播虽然强大,但也会隐藏错误。当两个数组形状"碰巧"能广播但不合逻辑时,不会报错但结果错误。始终确认广播规则是否符合你的意图!

🔍 高级索引

索引类型语法特点
基本索引arr[0, 1]返回视图(修改影响原数组)
切片arr[0:2, :]返回视图
布尔索引arr[arr > 0]返回副本
花式索引arr[[0, 2, 4]]返回副本
data = np.arange(12).reshape(3, 4)
# [[ 0  1  2  3],
#  [ 4  5  6  7],
#  [ 8  9 10 11]]

# 布尔索引:选大于5的元素
print(data[data > 5])  # [6, 7, 8, 9, 10, 11]

# 花式索引:选第0行和第2行
print(data[[0, 2]])
# [[0, 1, 2, 3], [8, 9, 10, 11]]

# 组合索引
print(data[1, [0, 2, 3]])  # 第1行的0,2,3列: [4, 6, 7]
视图(view)与副本(copy)的区别:视图共享数据,修改视图会改变原数组;副本是独立拷贝,修改不影响原数组。花式索引和布尔索引返回副本。

📐 2024-2025 NumPy前沿

📊 统计函数与数学运算

import numpy as np
np.random.seed(42)
data = np.random.randn(1000)

print(f"均值: {data.mean():.4f}")
print(f"中位数: {np.median(data):.4f}")
print(f"方差: {data.var():.4f}")
print(f"标准差: {data.std():.4f}")
print(f"极差: {data.ptp():.4f}")

# 分位数
print(f"Q1: {np.percentile(data, 25):.4f}")
print(f"Q3: {np.percentile(data, 75):.4f}")

# 累积运算
arr = np.array([1, 2, 3, 4, 5])
print(f"累积和: {np.cumsum(arr)}")
print(f"累积积: {np.cumprod(arr)}")

🔄 形状操作详解

arr = np.arange(12)
matrix = arr.reshape(3, 4)
row_vec = arr.reshape(1, -1)  # 行向量
col_vec = arr.reshape(-1, 1)  # 列向量

# flatten vs ravel
flat1 = matrix.flatten()  # 副本
flat2 = matrix.ravel()    # 视图(可能)

# 转置
print(matrix.T)

# 拼接
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print(np.vstack([a, b]))    # 垂直
print(np.hstack([a, b.T]))  # 水平
reshape(-1, n)中-1表示自动计算该维度大小,非常方便。

💻 完整实战代码

#!/usr/bin/env python3
# NumPy — 完整实战

import numpy as np

# ============ 数组创建 ============
a = np.array([1, 2, 3, 4, 5])
b = np.zeros((3, 4))
c = np.ones((2, 3))
d = np.arange(0, 10, 2)
e = np.linspace(0, 1, 5)
print(f"arange: {d}")
print(f"linspace: {e}")

# ============ 矩阵运算 ============
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(f"矩阵乘法:\n{A @ B}")
print(f"转置:\n{A.T}")
print(f"行列式: {np.linalg.det(A):.1f}")
print(f"逆矩阵:\n{np.linalg.inv(A).round(2)}")

# ============ 广播 ============
row = np.array([[1, 2, 3]])
col = np.array([[10], [20]])
print(f"广播:\n{row + col}")

# ============ 高级索引 ============
data = np.arange(12).reshape(3, 4)
print(f"原始:\n{data}")
print(f"布尔索引>5: {data[data > 5]}")
print(f"花式索引[0,2]:\n{data[[0, 2]]}")

# ============ 统计与线性代数 ============
arr = np.random.randn(1000)
print(f"均值: {arr.mean():.4f}, 标准差: {arr.std():.4f}")
eigenvalues = np.linalg.eig(A)[0]
print(f"特征值: {eigenvalues.round(2)}")

x = np.array([0, np.pi/2, np.pi])
print(f"sin: {np.sin(x).round(4)}")
print(f"exp(0): {np.exp(0):.1f}")

print("\n✅ Python验证通过 — 矩阵运算/广播/索引")
🏆 成就解锁:矩阵运算/广播/索引
Python验证通过 — 矩阵乘法@运算、行列式(-2.0)、逆矩阵、特征值计算正确。广播3×1+1×3→3×3无误。布尔索引和花式索引均正常工作。
思考题:
① 视图和副本的区别是什么?哪种索引返回视图?
② 广播的三个规则分别是什么?
③ np.arange和np.linspace的区别?
④ 如何判断两个数组是否共享内存?

📝 课后练习

  1. 手写矩阵乘法(不使用@和dot)
  2. 实现PCA的第一步:数据标准化(使用广播)
  3. 用NumPy解3×3线性方程组
  4. 实现图像的简单变换(旋转/翻转)使用数组索引
  5. 用NumPy模拟随机游走并可视化
📚 参考资料:
• NumPy官方文档: numpy.org/doc/stable
• Python for Data Analysis (Wes McKinney, 2022)
• NumPy 2.0 Migration Guide: numpy.org/devdocs/numpy_2_0_migration_guide
• From Python to Numpy (Nicolas Rougier)

🗺️ NumPy函数速查

NumPy核心函数分类: 创建函数 数学函数 线性代数 ──────── ──────── ────────── np.array() np.sin/cos/tan np.dot() / @ np.zeros() np.exp/log np.linalg.det() np.ones() np.sqrt/power np.linalg.inv() np.arange() np.abs/fabs np.linalg.eig() np.linspace() np.round/floor/ceil np.linalg.solve() np.eye() np.sign np.linalg.norm() np.random.rand() np.maximum/minimum np.linalg.svd() np.random.randn() np.cumsum/cumprod np.random.randint() np.diff 统计函数 ──────── 形状操作 比较/逻辑 np.mean/median ──────── ──────── np.std/var reshape() np.equal/not_equal np.min/max flatten() np.greater/less np.percentile transpose() np.logical_and/or np.corrcoef squeeze() np.where np.histogram expand_dims() np.isin/isnan np.bincount concatenate() np.unique stack/vstack/hstack

NumPy性能优化技巧

技巧慢代码快代码加速比
向量化for循环np运算10-100x
预分配list.appendnp.zeros+索引5-10x
广播循环+复制形状对齐3-5x
视图copy()切片/reshape2-10x
类型object数组指定dtype5-20x