NumPy: NumPy 入门

NumPy 是 Python 科学计算的基石。无论是机器学习、数据分析还是工程仿真,几乎所有数值计算库都建立在 NumPy 之上。本节将从 Python 列表的性能痛点出发,揭示 NumPy 速度快 160 倍的秘密,带你迈出数值计算的第一步。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。

1. 你将学到


2. Million-level 数据的提速之旅

(1) 痛点:Alice 的列表循环

Alice 是一名数据分析师,她需要对 1 million(1M)个随机数做平方运算。她写了一段"直觉上最自然"的 Python 代码——用 for 循环逐个处理列表元素。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:列表平方运算(难度⭐)

PYTHON
import time
import random

size = 1_000_000  # 1 million numbers
data = [random.random() for _ in range(size)]

start = time.time()
result = [x * x for x in data]
elapsed = time.time() - start

print(f"List comprehension: {elapsed:.4f} seconds")
# Typical output: List comprehension: 0.8000 seconds
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

Alice 的代码跑了约 0.8 秒。看似不长,但当她需要对上亿条数据反复运算时,等待时间会变得难以忍受。

(2) 解法:Bob 的 NumPy 向量化

Bob 只改了两行:用 np.array 替代列表,用一次向量乘法替代循环。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:NumPy 平方运算(难度⭐⭐)

PYTHON
import time
import numpy as np

size = 1_000_000  # 1 million numbers
data = np.random.random(size)

start = time.time()
result = data * data  # vectorized operation
elapsed = time.time() - start

print(f"NumPy vectorized: {elapsed:.4f} seconds")
# Typical output: NumPy vectorized: 0.0050 seconds
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

同样的 1 million 个数,NumPy 只需约 5 毫秒——快了约 160 倍

(3) 收益:160 倍提速的秘密

NumPy 的提速不是"Python 更快了",而是把计算交给了 C 语言和连续内存

这就是 NumPy 的核心哲学——用 Python 的便捷调用 C 的速度


3. Python 数值计算的痛点

(1) 循环开销:逐个解释执行

Python 是动态类型语言,每次循环迭代都要:检查类型 → 查找方法 → 执行运算 → 装箱结果。对于数值计算,这些额外步骤是纯粹的浪费。

PYTHON
# Each iteration: type check + method lookup + boxing
result = []
for x in data:          # Python loop overhead per iteration
    result.append(x * x)  # type check, method dispatch, result boxing
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

对比 C 语言编译后的机器码,一次 Python 循环的开销可以是实际乘法运算的 几十倍

(2) 类型开销:每个元素都是完整对象

Python 列表存储的不是"原始数字",而是 PyObject 指针。一个整数 42 在 Python 中占用 28 字节,而在 C 中只需 4 字节。


4. NumPy 的核心优势

(1) ndarray 是什么

ndarray(N-dimensional array)是 NumPy 的核心数据结构,它是一个:

(2) ndarray vs Python list

特性 Python list NumPy ndarray
元素类型 任意混合 同质(单一 dtype)
内存布局 指针数组,元素分散 连续内存块
单个 int 内存 28 字节(PyObject) 8 字节(int64)
批量运算 列表推导 / for 循环 向量化,一条语句
广播 不支持 自动扩展维度
切片视图 返回副本 默认返回视图(零拷贝)
多维支持 嵌套列表(不规则) 原生 N 维,shape 属性
底层实现 CPython 解释器 C / Fortran 编译代码

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:内存占用对比(难度⭐)

PYTHON
import sys
import numpy as np

size = 1_000_000  # 1 million integers

# Python list
py_list = list(range(size))
list_bytes = sys.getsizeof(py_list) + sum(sys.getsizeof(x) for x in py_list[:1000]) * size // 1000
print(f"Python list: ~{list_bytes / 1024 / 1024:.1f} MB")

# NumPy ndarray
np_array = np.arange(size, dtype=np.int64)
array_bytes = np_array.nbytes
print(f"NumPy ndarray: {array_bytes / 1024 / 1024:.1f} MB")

print(f"Ratio: {list_bytes / array_bytes:.1f}x more memory for list")
# Typical output:
# Python list: ~44.7 MB
# NumPy ndarray: 7.6 MB
# Ratio: 5.9x more memory for list
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

一个简单的 int64 ndarray 比同等规模的 Python 列表节省约 6 倍 内存——因为 ndarray 存的是原始数值,而不是完整的 Python 对象。

(3) 广播机制初探

"广播"(Broadcasting)让不同形状的数组之间直接运算,无需手动扩展。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:数组运算 vs 列表推导(难度⭐⭐)

PYTHON
import numpy as np

# Task: add 100 to every element and multiply by 2
data = [1, 2, 3, 4, 5]

# --- Python list ---
result_list = [(x + 100) * 2 for x in data]
print(result_list)
# [202, 204, 206, 208, 210]

# --- NumPy ndarray ---
arr = np.array(data)
result_np = (arr + 100) * 2  # broadcasting + vectorization
print(result_np)
# [202 204 206 208 210]

# With a 2D array and 1D array
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
# [[11 22 33]
#  [14 25 36]]
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

列表推导要写循环逻辑,NumPy 只需一行数学表达式——代码即公式


5. NumPy 生态系统概览

(1) NumPy 生态全景

NumPy 是整个 Python 科学计算生态的"地基"。几乎所有主流库都依赖它:

100%
mindmap
  root((NumPy Ecosystem))
    Data Science
      Pandas
      Polars
    Machine Learning
      Scikit-learn
      TensorFlow
      PyTorch
    Scientific Computing
      SciPy
      Matplotlib
      SymPy
    Deep Learning Frameworks
      Keras
      JAX
      MXNet
    Specialized Domains
      scikit-image
      NetworkX
      AstroPy
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

(2) 生态全景表

领域 依赖 NumPy 的原因
Pandas 数据分析 DataFrame 底层用 ndarray 存储列数据
Scikit-learn 机器学习 模型输入/输出均为 ndarray
SciPy 科学计算 基于 ndarray 提供线性代数/优化/积分
Matplotlib 可视化 绘图数据源为 ndarray
TensorFlow 深度学习 张量概念源自 ndarray,可互转
PyTorch 深度学习 Tensor 与 ndarray 互相转换
Polars 数据分析 列式存储,但仍兼容 NumPy

(3) 数值计算场景对比

场景 纯 Python NumPy 推荐
几十个数的简单运算 够用 略快 纯 Python
10K+ 数值的批量运算 快 10~100x NumPy
矩阵乘法 嵌套循环极慢 调用 BLAS 极快 NumPy
线性方程组 手写不现实 np.linalg.solve NumPy
字符串处理 灵活 不擅长 纯 Python
混合类型数据 list 天然支持 需结构化数组 视情况

6. 安装与第一个程序

(1) 安装方式对比

方式 命令 适用场景
pip pip install numpy 通用,最简单
conda conda install numpy Anaconda/Miniconda 环境
系统包管理 apt install python3-numpy Linux 系统级安装
源码编译 python setup.py build 需要自定义 BLAS 后端

推荐新手使用 pip install numpy,Anaconda 用户用 conda install numpy

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:安装验证(难度⭐)

BASH
# Install
pip install numpy

# Verify
python -c "import numpy as np; print(np.__version__)"
# Output (example): 2.1.0
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

(2) 创建第一个 ndarray

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:np.array 创建(难度⭐)

PYTHON
import numpy as np

# From a Python list
a = np.array([1, 2, 3, 4, 5])
print(type(a))   # <class 'numpy.ndarray'>
print(a.dtype)   # int64
print(a.shape)   # (5,)

# From nested list (2D)
b = np.array([[1, 2, 3],
              [4, 5, 6]])
print(b.shape)   # (2, 3)
print(b.ndim)    # 2

# Specify dtype explicitly
c = np.array([1, 2, 3], dtype=np.float32)
print(c.dtype)   # float32
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

(3) 查看版本与配置

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:查看版本和配置(难度⭐)

PYTHON
import numpy as np

print(f"NumPy version: {np.__version__}")

# Show build configuration (BLAS, LAPACK, etc.)
np.show_config()
# Output includes: BLAS, LAPACK backend info,
# which determines computation performance
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

np.show_config() 输出的 BLAS/LAPACK 信息决定了你的 NumPy 在矩阵运算上能跑多快——OpenBLAS、MKL 等不同后端性能差异可达数倍。


7. 综合实战:10M 数据的均值与标准差

面对 10 million 个浮点数,计算均值和标准差——这是数据分析最常见的操作之一。我们用纯 Python 和 NumPy 分别实现,对比代码量速度内存

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。

:综合对比——列表 vs NumPy(难度⭐⭐⭐)

PYTHON
import time
import math
import random
import numpy as np
import sys

size = 10_000_000  # 10 million

# ========== Pure Python ==========
py_data = [random.random() for _ in range(size)]

t0 = time.time()
mean_py = sum(py_data) / len(py_data)
var_py = sum((x - mean_py) ** 2 for x in py_data) / len(py_data)
std_py = math.sqrt(var_py)
elapsed_py = time.time() - t0

# Memory estimate for list
mem_py = sys.getsizeof(py_data) + size * 24  # ~24 bytes per float object

# ========== NumPy ==========
np_data = np.random.random(size)

t0 = time.time()
mean_np = np.mean(np_data)
std_np = np.std(np_data)
elapsed_np = time.time() - t0

# Memory for ndarray
mem_np = np_data.nbytes

# ========== Results ==========
print(f"--- Pure Python ---")
print(f"  Mean: {mean_py:.6f}  Std: {std_py:.6f}")
print(f"  Time: {elapsed_py:.3f}s")
print(f"  Memory: ~{mem_py / 1024 / 1024:.0f} MB")

print(f"--- NumPy ---")
print(f"  Mean: {mean_np:.6f}  Std: {std_np:.6f}")
print(f"  Time: {elapsed_np:.3f}s")
print(f"  Memory: {mem_np / 1024 / 1024:.1f} MB")

print(f"--- Comparison ---")
print(f"  Speedup: {elapsed_py / elapsed_np:.1f}x")
print(f"  Memory saving: {mem_py / mem_np:.1f}x")
# Typical output:
# --- Pure Python ---
#   Mean: 0.500032  Std: 0.288675
#   Time: 3.200s
#   Memory: ~305 MB
# --- NumPy ---
#   Mean: 0.500032  Std: 0.288675
#   Time: 0.030s
#   Memory: 76.3 MB
# --- Comparison ---
#   Speedup: 106.7x
#   Memory saving: 4.0x
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境运行 NumPy 2.x,输出 ndarray 数组内容。Piston 服务器未预装 NumPy,请在本机安装(`pip install numpy`)后实操对照。实际数值可能因 NumPy 版本、随机种子略有差异。
指标 纯 Python NumPy 对比
代码行数(核心逻辑) 4 行 2 行 NumPy 少 50%
执行时间 ~3.2s ~0.03s 快 ~100x
内存占用 ~305 MB ~76 MB 省 4x

结论:数据量越大,NumPy 的优势越明显。在 10 million 级别的数据上,NumPy 在速度和内存上都碾压纯 Python。


❓ 常见问题

Q NumPy 和 Python 是什么关系?
A NumPy 是 Python 的第三方库,不是 Python 标准库的一部分。它用 C 语言编写核心计算引擎,通过 Python 接口调用,让你在 Python 中享受接近 C 的速度。
Q 为什么 NumPy 比列表快这么多?
A 三个原因——①底层 C 实现绕过 Python 解释器开销;②连续内存布局让 CPU 缓存高效命中;③向量化运算一条指令处理整个数组,无需逐元素循环。
Q 使用 NumPy 需要学 C 语言吗?
A 不需要。NumPy 的设计目标就是让 Python 用户以 Python 语法享受 C 级速度。只有当你想给 NumPy 贡献底层代码或编写自定义 C 扩展时才需要 C。
Q NumPy 能替代 Excel 吗?
A 对于数值计算和批量数据处理,NumPy 远比 Excel 强大且高效。但 NumPy 不提供表格 UI、图表拖拽等交互功能,通常需要搭配 Pandas(表格式数据)和 Matplotlib(可视化)一起使用。
Q NumPy 2.x 和 1.x 有什么区别?
A NumPy 2.0(2024 年发布)主要改进了 C API 的稳定性、新增了一些字符串运算 API、改善了 dtype 系统。对于日常 Python 使用者,API 变化很小,大部分 1.x 代码可以无缝迁移。建议新项目直接使用 2.x。
Q ndarray 和 Python 的 array 模块有什么区别?
A Python 标准库的 array 模块只支持 1D 同类型数组,没有广播、线性代数、FFT 等功能。NumPy 的 ndarray 支持多维、广播、丰富的数学函数,是两个完全不同量级的工具。

📖 小节


📝 作业

  1. 基础题(难度⭐):安装 NumPy 并运行 import numpy as np; print(np.__version__),确认版本号 ≥ 1.24。将输出结果记录下来。

  2. 进阶题(难度⭐⭐):生成一个包含 5 million 个随机数的列表和一个 ndarray,分别用列表推导和 NumPy 向量化计算每个数的平方加 10,用 time.time() 计时并对比耗时。记录两者的耗时比。

  3. 挑战题(难度⭐⭐⭐):运行 np.show_config(),找到你安装的 NumPy 使用的 BLAS 后端(OpenBLAS / MKL / 其他),并查阅资料简述该后端对你的矩阵运算性能的影响。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏