杰瑞科技汇

numpy教程该怎么学?

NumPy 完整教程:从入门到精通

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

numpy教程该怎么学?-图1
(图片来源网络,侵删)

本教程将带你一步步掌握 NumPy 的核心概念和常用操作。


目录

  1. 为什么是 NumPy?
  2. 安装与导入
  3. 核心概念:NumPy 数组
  4. 创建数组
  5. 数组属性
  6. 数据类型
  7. 索引与切片
  8. 数组运算
  9. 广播机制
  10. 聚合函数
  11. 常用数学函数
  12. 文件 I/O
  13. 实践案例:从列表到数组的性能对比
  14. 总结与后续学习

为什么是 NumPy?

在 NumPy 出现之前,Python 主要用于通用编程,要进行科学计算,人们通常使用 Python 的列表,但列表存在以下问题:

  • 性能低下:列表是 Python 对象的数组,每个元素都是一个独立的 Python 对象,这带来了大量的内存和计算开销。
  • 功能有限:列表内置的数学运算功能非常少,无法高效地进行向量化计算。

NumPy 通过引入 同构数据数组 解决了这些问题:

  • 高性能:NumPy 数组在内存中是连续存储的,并且所有元素都是相同的数据类型,这使得它在底层使用 C 语言实现,运算速度极快。
  • 丰富的函数库:NumPy 提供了大量的数学、逻辑、形状操作、排序、选择、离散傅里叶变换、基本线性代数、基本统计运算等功能。
  • 向量化操作:可以对整个数组执行操作,无需编写循环,代码更简洁、高效。

安装与导入

你需要安装 NumPy,如果你已经安装了 Anaconda,NumPy 通常已经包含在内,如果没有,可以使用 pip 安装:

numpy教程该怎么学?-图2
(图片来源网络,侵删)
pip install numpy

在 Python 代码中,按照惯例,我们通常使用 np 作为 NumPy 的别名:

import numpy as np

核心概念:NumPy 数组

NumPy 的核心是 ndarray (N-dimensional Array) 对象,即 N 维数组。

与 Python 列表不同,NumPy 数组要求所有元素的数据类型必须相同。


创建数组

从 Python 列表创建

这是最常见的方式。

numpy教程该怎么学?-图3
(图片来源网络,侵删)
# 创建一维数组
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, int64
  • uint8, uint16, uint32, uint64 (无符号整数)
  • float16, float32, float64
  • complex64, 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. 对齐维度:从后向前比较两个数组的维度。
  2. 维度兼容:如果两个维度大小相同,或者其中一个维度为 1,则它们是兼容的。
  3. 扩展维度:如果一个数组的维度比另一个小,它会在前面补 1。
  4. 复制数据:维度为 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。

下一步学习建议:

  1. Matplotlib:学习使用 Matplotlib 进行数据可视化,NumPy 数组是 Matplotlib 的主要数据输入。
  2. Pandas:学习 Pandas 库,它基于 NumPy,提供了更高级的数据结构和分析工具,特别适合处理表格数据。
  3. Scikit-learn:如果你对机器学习感兴趣,Scikit-learn 是一个基于 NumPy 和 SciPy 的强大库,几乎所有算法的输入都是 NumPy 数组。
  4. 深入 NumPy 官方文档NumPy User Guide 是最权威和全面的资源,当你遇到特定问题时,查阅官方文档是最好的方式。

希望这份教程对你有帮助!祝你学习愉快!

分享:
扫描分享到社交APP
上一篇
下一篇