NumPy 完整教程:从入门到精通
NumPy (Numerical Python) 是 Python 科学计算的核心库,它提供了一个强大的 N 维数组对象,以及各种用于操作这些数组的工具,NumPy 是许多高级科学计算库(如 Pandas, Scikit-learn, TensorFlow, PyTorch)的基础。

本教程将带你一步步掌握 NumPy 的核心概念和常用操作。
目录
- 为什么是 NumPy?
- 安装与导入
- 核心概念:NumPy 数组
- 创建数组
- 数组属性
- 数据类型
- 索引与切片
- 数组运算
- 广播机制
- 聚合函数
- 常用数学函数
- 文件 I/O
- 实践案例:从列表到数组的性能对比
- 总结与后续学习
为什么是 NumPy?
在 NumPy 出现之前,Python 主要用于通用编程,要进行科学计算,人们通常使用 Python 的列表,但列表存在以下问题:
- 性能低下:列表是 Python 对象的数组,每个元素都是一个独立的 Python 对象,这带来了大量的内存和计算开销。
- 功能有限:列表内置的数学运算功能非常少,无法高效地进行向量化计算。
NumPy 通过引入 同构数据数组 解决了这些问题:
- 高性能:NumPy 数组在内存中是连续存储的,并且所有元素都是相同的数据类型,这使得它在底层使用 C 语言实现,运算速度极快。
- 丰富的函数库:NumPy 提供了大量的数学、逻辑、形状操作、排序、选择、离散傅里叶变换、基本线性代数、基本统计运算等功能。
- 向量化操作:可以对整个数组执行操作,无需编写循环,代码更简洁、高效。
安装与导入
你需要安装 NumPy,如果你已经安装了 Anaconda,NumPy 通常已经包含在内,如果没有,可以使用 pip 安装:

pip install numpy
在 Python 代码中,按照惯例,我们通常使用 np 作为 NumPy 的别名:
import numpy as np
核心概念:NumPy 数组
NumPy 的核心是 ndarray (N-dimensional Array) 对象,即 N 维数组。
与 Python 列表不同,NumPy 数组要求所有元素的数据类型必须相同。
创建数组
从 Python 列表创建
这是最常见的方式。

# 创建一维数组
arr1d = np.array([1, 2, 3, 4, 5])
print("一维数组:\n", arr1d)
# 创建二维数组 (矩阵)
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print("\n二维数组:\n", arr2d)
# 创建三维数组
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("\n三维数组:\n", arr3d)
使用内置函数创建
NumPy 提供了许多便捷的函数来创建特定类型的数组。
# 创建一个全为 0 的数组
zeros_arr = np.zeros((3, 4)) # 形状为 3行4列
print("全零数组:\n", zeros_arr)
# 创建一个全为 1 的数组
ones_arr = np.ones((2, 3))
print("\n全一数组:\n", ones_arr)
# 创建一个指定范围的数组,类似 range()
range_arr = np.arange(10) # 0 到 9
print("\n范围数组:\n", range_arr)
# 创建一个线性等分空间数组
linspace_arr = np.linspace(0, 1, 5) # 在 0 和 1 之间创建 5 个等距点
print("\n等分空间数组:\n", linspace_arr)
# 创建一个单位矩阵
identity_matrix = np.eye(3)
print("\n单位矩阵:\n", identity_matrix)
# 创建一个随机数组
random_arr = np.random.rand(3, 2) # 生成一个 3x2 的 [0, 1) 之间的随机数矩阵
print("\n随机数组:\n", random_arr)
数组属性
了解数组的属性对于操作数组至关重要。
a = np.array([[1, 2, 3], [4, 5, 6]])
# ndim: 维度数量
print("维度数量:", a.ndim) # 输出: 2
# shape: 数组的形状(每个维度的大小)
print("数组形状:", a.shape) # 输出: (2, 3)
# size: 数组中元素的总数
print("元素总数:", a.size) # 输出: 6
# dtype: 数组元素的数据类型
print("数据类型:", a.dtype) # 输出: int64 (默认)
# itemsize: 每个元素占用的字节数
print("每个元素字节数:", a.itemsize) # 输出: 8 (int64 占 8 字节)
# nbytes: 整个数组占用的字节数
print("数组总字节数:", a.nbytes) # 输出: 48 (6 * 8)
数据类型
NumPy 提供了比 Python 更丰富的数据类型。
# 指定数据类型
b = np.array([1, 2, 3], dtype=np.float32)
print("数组 b:", b)
print("数组 b 的数据类型:", b.dtype) # 输出: float32
# 转换数据类型
c = b.astype(np.int32)
print("转换后的数组 c:", c)
print("数组 c 的数据类型:", c.dtype) # 输出: int32
常用数据类型:
int8, int16, int32, int64uint8, uint16, uint32, uint64(无符号整数)float16, float32, float64complex64, complex128(复数)bool(布尔型)
索引与切片
NumPy 的索引和切片语法与 Python 列表非常相似,但功能更强大。
一维数组
arr = np.array([0, 10, 20, 30, 40, 50])
# 索引
print("第一个元素:", arr[0]) # 输出: 0
print("最后一个元素:", arr[-1]) # 输出: 50
# 切片
print("从索引 1 到 4:", arr[1:5]) # 输出: [10 20 30 40]
print("从开头到索引 3:", arr[:4]) # 输出: [ 0 10 20 30]
print("从索引 2 到末尾:", arr[2:]) # 输出: [20 30 40 50]
多维数组
对于多维数组,使用逗号 分隔不同维度的索引。
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 获取单个元素
print("第 1 行第 2 列的元素:", arr2d[0, 1]) # 输出: 2
# 获取整行或整列
print("第 1 行:", arr2d[0, :]) # 或 arr2d[0]
print("第 2 列:", arr2d[:, 1])
# 获取子数组
print("左上角的 2x2 子数组:\n", arr2d[:2, :2])
布尔索引
这是一种非常强大的功能,可以根据条件筛选元素。
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
# 创建一个布尔掩码
mask = arr > 5
print("布尔掩码:", mask) # 输出: [False False False False False True True True]
# 使用掩码筛选元素
print("大于 5 的元素:", arr[mask])
数组运算
这是 NumPy 最强大的地方——向量化运算,你可以对整个数组进行数学运算,而无需编写循环。
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# 加法
print("a + b:", a + b) # 输出: [11 22 33 44]
# 减法
print("b - a:", b - a) # 输出: [ 9 18 27 36]
# 乘法 (对应元素相乘)
print("a * b:", a * b) # 输出: [ 10 40 90 160]
# 除法
print("b / a:", b / a) # 输出: [10. 10. 10. 10.]
# 标量运算
print("a * 2:", a * 2) # 输出: [ 2 4 6 8]
print("a ** 2:", a ** 2) # 输出: [ 1 4 9 16]
广播机制
当两个形状不同的数组进行运算时,NumPy 会尝试通过“广播”使它们的形状兼容,广播的规则如下:
- 对齐维度:从后向前比较两个数组的维度。
- 维度兼容:如果两个维度大小相同,或者其中一个维度为 1,则它们是兼容的。
- 扩展维度:如果一个数组的维度比另一个小,它会在前面补 1。
- 复制数据:维度为 1 的维度会被“拉伸”或“复制”以匹配另一个数组的维度大小。
# 标量与数组
a = np.array([1, 2, 3])
# a + 5 实际上是 a + [5, 5, 5]
print("a + 5:", a + 5) # 输出: [6 7 8]
# 形状不同的数组
# a 是 (3,),b 是 (3, 1)
a = np.array([1, 2, 3])
b = np.array([[10], [20], [30]])
# a 的形状被广播为 (3, 1)
# b 的形状是 (3, 1)
# 运算结果形状为 (3, 3)
# a = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
# b = [[10, 10, 10], [20, 20, 20], [30, 30, 30]]
print("a + b:\n", a + b)
聚合函数
这些函数对数组中的元素进行计算,并返回一个标量值。
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 求和
print("所有元素的和:", np.sum(arr)) # 输出: 21
print("按列求和:", np.sum(arr, axis=0)) # 输出: [5 7 9]
print("按行求和:", np.sum(arr, axis=1)) # 输出: [ 6 15]
# 最大值/最小值
print("最大值:", np.max(arr))
print("最小值:", np.min(arr))
print("按列最大值:", np.max(arr, axis=0))
# 平均值
print("平均值:", np.mean(arr))
# 标准差
print("标准差:", np.std(arr))
# 中位数
print("中位数:", np.median(arr))
常用数学函数
NumPy 提供了大量的数学函数,如三角函数、指数、对数等。
arr = np.array([0, np.pi/2, np.pi])
# 三角函数
print("sin(arr):", np.sin(arr))
print("cos(arr):", np.cos(arr))
# 指数和对数
arr_exp = np.array([1, 2, 3])
print("e^x:", np.exp(arr_exp))
print("ln(x):", np.log(arr_exp))
print("log10(x):", np.log10(arr_exp))
文件 I/O
NumPy 可以轻松地将数组保存到文件和从文件加载。
arr = np.arange(10)
# 保存为 .npy 文件 (NumPy 专有格式)
np.save('my_array.npy', arr)
# 从 .npy 文件加载
loaded_arr = np.load('my_array.npy')
print("从文件加载的数组:", loaded_arr)
# 保存多个数组到 .npz 文件
b = np.arange(5)
np.savez('my_arrays.npz', array_a=arr, array_b=b)
# 从 .npz 文件加载
data = np.load('my_arrays.npz')
print("从 npz 文件加载的 array_a:", data['array_a'])
print("从 npz 文件加载的 array_b:", data['array_b'])
# 保存为文本文件 (如 CSV)
np.savetxt('my_array.txt', arr, delimiter=',')
loaded_txt_arr = np.loadtxt('my_array.txt', delimiter=',')
print("从文本文件加载的数组:", loaded_txt_arr)
实践案例:从列表到数组的性能对比
让我们通过一个简单的例子来感受 NumPy 的威力:计算两个向量的点积。
import time
import numpy as np
# 准备数据
size = 1000000
python_list_a = list(range(size))
python_list_b = list(range(size))
numpy_array_a = np.arange(size)
numpy_array_b = np.arange(size)
# 使用 Python 列表和循环
start_time = time.time()
dot_product_list = sum([a * b for a, b in zip(python_list_a, python_list_b)])
end_time = time.time()
print(f"Python 列表循环耗时: {(end_time - start_time) * 1000:.4f} 毫秒")
# 使用 NumPy
start_time = time.time()
dot_product_numpy = np.dot(numpy_array_a, numpy_array_b)
end_time = time.time()
print(f"NumPy 向量化耗时: {(end_time - start_time) * 1000:.4f} 毫秒")
# 验证结果
print("\n结果是否相等:", dot_product_list == dot_product_numpy)
在我的机器上,NumPy 的速度通常是 Python 列表循环的 50 到 100 倍,甚至更多,这就是为什么在科学计算中,NumPy 是不可或缺的工具。
总结与后续学习
本教程涵盖了 NumPy 的核心知识,你已经学会了:
- NumPy 的基本概念和优势。
- 如何创建、索引和操作 NumPy 数组。
- 如何利用向量化运算和广播机制进行高效的数学计算。
- 如何使用聚合函数和数学函数。
- 如何进行文件 I/O。
下一步学习建议:
- Matplotlib:学习使用 Matplotlib 进行数据可视化,NumPy 数组是 Matplotlib 的主要数据输入。
- Pandas:学习 Pandas 库,它基于 NumPy,提供了更高级的数据结构和分析工具,特别适合处理表格数据。
- Scikit-learn:如果你对机器学习感兴趣,Scikit-learn 是一个基于 NumPy 和 SciPy 的强大库,几乎所有算法的输入都是 NumPy 数组。
- 深入 NumPy 官方文档:NumPy User Guide 是最权威和全面的资源,当你遇到特定问题时,查阅官方文档是最好的方式。
希望这份教程对你有帮助!祝你学习愉快!
