NumPy (Numerical Python) 是 Python 中科学计算的基础库。它提供了一个强大的多维数组对象ndarray,以及大量的数学函数来操作这些数组。NumPy 数组运算效率高,语法简洁,是数据分析、机器学习等领域不可或缺的工具。
本文将通过常用案例,帮助你快速掌握 NumPy 的核心用法。每个案例都包含代码示例和详细解释,确保代码可以直接运行。
准备工作
首先,确保你已经安装了 NumPy。如果没有安装,可以使用 pip 进行安装:
pip install numpy
- 1.
安装完成后,在 Python 代码中导入 NumPy 库,通常简写为 np:
import numpy as np
- 1.
1. 创建NumPy数组(ndarray)
NumPy 的核心是 ndarray 对象,可以使用多种方式创建数组。
# 案例1:从 Python 列表创建数组
list1 = [1, 2, 3, 4, 5]
arr1 = np.array(list1)
print("案例1 - 从列表创建数组:", arr1)
print("数组类型:", type(arr1)) # 查看数组类型,是 numpy.ndarray
print("数组数据类型:", arr1.dtype) # 查看数组元素的数据类型,默认是 int64 (或 int32 等,取决于系统)
# 案例2:创建多维数组(矩阵)
list2 = [[1, 2, 3], [4, 5, 6]]
arr2 = np.array(list2)
print("\n案例2 - 创建多维数组:\n", arr2)
print("数组维度:", arr2.ndim) # 查看数组维度,二维数组是 2
print("数组形状:", arr2.shape) # 查看数组形状,(2, 3) 表示 2 行 3 列
print("数组元素个数:", arr2.size) # 查看数组元素总数,2 * 3 = 6
# 案例3:创建指定形状的零数组
zeros_arr = np.zeros((3, 4)) # 创建 3 行 4 列的零数组
print("\n案例3 - 创建零数组:\n", zeros_arr)
# 案例4:创建指定形状的单位数组
ones_arr = np.ones((2, 3), dtype=int) # 创建 2 行 3 列的单位数组,指定数据类型为整数
print("\n案例4 - 创建单位数组:\n", ones_arr)
print("单位数组数据类型:", ones_arr.dtype)
# 案例5:创建指定范围的数组 (arange)
range_arr = np.arange(0, 10, 2) # 创建从 0 到 10 (不包含 10),步长为 2 的数组
print("\n案例5 - 创建指定范围数组 (arange):\n", range_arr)
# 案例6:创建指定数量的均匀间隔数组 (linspace)
linspace_arr = np.linspace(0, 1, 5) # 创建从 0 到 1 (包含 1),均匀间隔 5 个元素的数组
print("\n案例6 - 创建均匀间隔数组 (linspace):\n", linspace_arr)
# 案例7:创建随机数数组 (random)
rand_arr = np.random.rand(2, 2) # 创建 2 行 2 列的 0-1 之间均匀分布的随机数数组
print("\n案例7 - 创建随机数数组 (均匀分布):\n", rand_arr)
randn_arr = np.random.randn(3) # 创建 3 个服从标准正态分布的随机数数组
print("\n案例7 - 创建随机数数组 (正态分布):\n", randn_arr)
randint_arr = np.random.randint(1, 10, size=(2, 3)) # 创建 2 行 3 列的 1-10 之间(不包含10)的随机整数数组
print("\n案例7 - 创建随机整数数组:\n", randint_arr)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
2. 数组的基本操作
NumPy数组支持各种数学运算,这些运算通常是元素级别的。
arr_a = np.array([1, 2, 3])
arr_b = np.array([4, 5, 6])
# 案例8:数组的加法、减法、乘法、除法 (元素级别)
print("\n案例8 - 数组的基本运算:")
print("数组 a:", arr_a)
print("数组 b:", arr_b)
print("加法 (a + b):", arr_a + arr_b)
print("减法 (a - b):", arr_a - arr_b)
print("乘法 (a * b):", arr_a * arr_b)
print("除法 (a / b):", arr_a / arr_b)
print("标量乘法 (a * 2):", arr_a * 2) # 数组与标量运算
# 案例9:数组的平方、平方根、指数、对数 (元素级别)
print("\n案例9 - 数组的数学函数:")
print("平方 (a ** 2):", arr_a ** 2)
print("平方根 (np.sqrt(a)):", np.sqrt(arr_a))
print("指数 (np.exp(a)):", np.exp(arr_a))
print("自然对数 (np.log(a)):", np.log(arr_a))
print("正弦 (np.sin(a)):", np.sin(arr_a)) # 其他三角函数 np.cos, np.tan 等
# 案例10:数组的比较运算 (元素级别)
print("\n案例10 - 数组的比较运算:")
print("a > 2:", arr_a > 2) # 返回布尔数组
print("a == b:", arr_a == arr_b)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
3. 数组的索引和切片
NumPy 数组的索引和切片操作与 Python 列表类似,但功能更强大。
arr_c = np.arange(10) # 创建 0-9 的数组
print("\n案例11 - 数组的索引和切片:")
print("数组 c:", arr_c)
# 索引
print("索引 0:", arr_c[0])
print("索引 -1 (最后一个元素):", arr_c[-1])
# 切片
print("切片 [2:5]:", arr_c[2:5]) # 索引 2, 3, 4 的元素
print("切片 [:5]:", arr_c[:5]) # 从开始到索引 4 的元素
print("切片 [5:]:", arr_c[5:]) # 从索引 5 到结尾的元素
print("切片 [::2]:", arr_c[::2]) # 从开始到结尾,步长为 2 的元素
# 多维数组的索引和切片
arr_d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print("\n多维数组 d:\n", arr_d)
print("d[0, 0]:", arr_d[0, 0]) # 第一行第一列元素
print("d[1, :]:", arr_d[1, :]) # 第二行所有列 (或 d[1])
print("d[:, 2]:", arr_d[:, 2]) # 所有行第三列
print("d[0:2, 1:3]:\n", arr_d[0:2, 1:3]) # 切片子矩阵 (0,1行 和 1,2列)
# 布尔索引 (使用条件筛选元素)
bool_index = arr_c > 5
print("\n布尔索引 (arr_c > 5):\n", bool_index)
print("根据布尔索引筛选元素:", arr_c[bool_index]) # 只选择 True 对应的元素
print("更简洁的写法:", arr_c[arr_c > 5]) # 直接使用条件作为索引
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
4. 数组的形状操作
可以改变数组的形状,但不改变数据本身。
arr_e = np.arange(12)
print("\n案例12 - 数组的形状操作:")
print("原始数组 e:", arr_e)
print("原始数组形状:", arr_e.shape)
# reshape: 改变数组形状 (返回新数组,不修改原数组)
reshaped_arr = arr_e.reshape(3, 4) # 变为 3 行 4 列
print("\nreshape 成 (3, 4):\n", reshaped_arr)
print("reshape 后的数组形状:", reshaped_arr.shape)
print("原始数组 e (未改变):\n", arr_e)
# resize: 改变数组形状 (修改原数组)
arr_e.resize(4, 3) # 变为 4 行 3 列,会修改 arr_e 本身
print("\nresize 成 (4, 3) 后,数组 e:\n", arr_e)
print("resize 后的数组形状:", arr_e.shape)
# flatten: 展平数组 (返回一维数组)
flattened_arr = reshaped_arr.flatten() # 或使用 .ravel()
print("\n展平数组 (flatten):\n", flattened_arr)
print("展平后的数组形状:", flattened_arr.shape)
# transpose: 转置数组 (交换维度,对于二维数组就是行列互换)
arr_f = np.array([[1, 2, 3], [4, 5, 6]])
print("\n原始数组 f:\n", arr_f)
transposed_arr = arr_f.T # 或使用 np.transpose(arr_f)
print("\n转置后的数组 f.T:\n", transposed_arr)
print("转置后的数组形状:", transposed_arr.shape)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
5. 数组的聚合函数
NumPy 提供了很多聚合函数,用于对数组进行统计计算。
arr_g = np.array([[1, 2, 3], [4, 5, 6]])
print("\n案例13 - 数组的聚合函数:")
print("数组 g:\n", arr_g)
# 求和
print("所有元素求和 (np.sum(g)):", np.sum(arr_g))
print("按列求和 (np.sum(g, axis=0)):", np.sum(arr_g, axis=0)) # axis=0 表示按列 (沿着行的方向求和)
print("按行求和 (np.sum(g, axis=1)):", np.sum(arr_g, axis=1)) # axis=1 表示按行 (沿着列的方向求和)
# 求均值
print("\n所有元素均值 (np.mean(g)):", np.mean(arr_g))
print("按列均值 (np.mean(g, axis=0)):", np.mean(arr_g, axis=0))
print("按行均值 (np.mean(g, axis=1)):", np.mean(arr_g, axis=1))
# 求最大值、最小值
print("\n最大值 (np.max(g)):", np.max(arr_g))
print("按列最大值 (np.max(g, axis=0)):", np.max(arr_g, axis=0))
print("最小值 (np.min(g)):", np.min(arr_g))
print("按行最小值 (np.min(g, axis=1)):", np.min(arr_g, axis=1))
# 其他聚合函数:
print("\n标准差 (np.std(g)):", np.std(arr_g))
print("方差 (np.var(g)):", np.var(arr_g))
print("中位数 (np.median(g)):", np.median(arr_g)) # 注意:中位数不是聚合函数,但常用于统计
print("乘积 (np.prod(g)):", np.prod(arr_g)) # 所有元素乘积
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
6. 数组的合并与分割
可以将多个数组合并成一个,也可以将一个数组分割成多个。
arr_h1 = np.array([[1, 2], [3, 4]])
arr_h2 = np.array([[5, 6], [7, 8]])
print("\n案例14 - 数组的合并:")
print("数组 h1:\n", arr_h1)
print("数组 h2:\n", arr_h2)
# concatenate: 沿指定轴连接数组
concat_axis0 = np.concatenate((arr_h1, arr_h2), axis=0) # 沿 axis=0 (垂直方向,行) 连接
print("\nconcatenate (axis=0):\n", concat_axis0)
concat_axis1 = np.concatenate((arr_h1, arr_h2), axis=1) # 沿 axis=1 (水平方向,列) 连接
print("\nconcatenate (axis=1):\n", concat_axis1)
# vstack: 垂直堆叠数组 (相当于 concatenate axis=0)
vstack_arr = np.vstack((arr_h1, arr_h2))
print("\nvstack (垂直堆叠):\n", vstack_arr)
# hstack: 水平堆叠数组 (相当于 concatenate axis=1)
hstack_arr = np.hstack((arr_h1, arr_h2))
print("\nhstack (水平堆叠):\n", hstack_arr)
# split: 分割数组
arr_i = np.arange(10)
print("\n案例15 - 数组的分割:")
print("数组 i:", arr_i)
split_arr = np.split(arr_i, 2) # 分割成 2 个子数组 (均匀分割)
print("\nsplit 成 2 个子数组:\n", split_arr)
split_arr_indices = np.split(arr_i, [3, 7]) # 在索引 3 和 7 的位置分割
print("\nsplit 在索引 [3, 7] 位置:\n", split_arr_indices) # 分割成 3 个子数组
vsplit_arr = np.vsplit(vstack_arr, 2) # 垂直分割多维数组
print("\nvsplit 多维数组 (vstack_arr):\n", vsplit_arr)
hsplit_arr = np.hsplit(hstack_arr, 2) # 水平分割多维数组
print("\nhsplit 多维数组 (hstack_arr):\n", hsplit_arr)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
7. 数组的广播 (Broadcasting)
NumPy 的广播机制允许不同形状的数组进行算术运算。
arr_j1 = np.array([1, 2, 3])
scalar = 3
print("\n案例16 - 数组的广播 (Broadcasting):")
print("数组 j1:", arr_j1)
print("标量:", scalar)
# 数组与标量相加 (标量广播到数组的每个元素)
broadcast_add = arr_j1 + scalar
print("\n数组 + 标量:", broadcast_add)
arr_j2 = np.array([[1, 2, 3], [4, 5, 6]])
arr_j3 = np.array([10, 20, 30]) # (3,) 形状的数组
print("\n数组 j2:\n", arr_j2)
print("数组 j3:", arr_j3)
# 形状不同的数组相加 (j3 广播到 j2 的每一行)
broadcast_add_arr = arr_j2 + arr_j3
print("\n形状不同的数组相加 (广播):\n", broadcast_add_arr) # j3 会被广播成 [[10, 20, 30], [10, 20, 30]] 再与 j2 相加
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
8. 线性代数运算
NumPy 提供了基本的线性代数运算功能。
arr_k1 = np.array([[1, 2], [3, 4]])
arr_k2 = np.array([[5, 6], [7, 8]])
print("\n案例17 - 线性代数运算:")
print("数组 k1:\n", arr_k1)
print("数组 k2:\n", arr_k2)
# 矩阵乘法 (dot product)
matrix_multiply = np.dot(arr_k1, arr_k2) # 或使用 arr_k1 @ arr_k2 (Python 3.5+ 支持)
print("\n矩阵乘法 (k1 * k2):\n", matrix_multiply)
# 矩阵转置 (前面案例已演示: .T 或 np.transpose())
# 矩阵的逆 (inverse)
from numpy.linalg import inv
try:
inv_k1 = inv(arr_k1)
print("\n矩阵 k1 的逆:\n", inv_k1)
except np.linalg.LinAlgError:
print("\n矩阵 k1 不可逆 (奇异矩阵)")
# 行列式 (determinant)
from numpy.linalg import det
det_k1 = det(arr_k1)
print("\n矩阵 k1 的行列式:", det_k1)
# 特征值和特征向量 (eigenvalues and eigenvectors)
from numpy.linalg import eig
eigenvalues, eigenvectors = eig(arr_k1)
print("\n矩阵 k1 的特征值:", eigenvalues)
print("\n矩阵 k1 的特征向量:\n", eigenvectors)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
9. 文件 I/O
NumPy 可以将数组保存到文件,也可以从文件加载数组。
arr_l = np.arange(10)
print("\n案例18 - 文件 I/O:")
print("数组 l:", arr_l)
# 保存数组到文件 (二进制格式 .npy)
np.save('my_array.npy', arr_l)
print("\n数组已保存到 my_array.npy")
# 从文件加载数组
loaded_arr = np.load('my_array.npy')
print("\n从 my_array.npy 加载的数组:", loaded_arr)
print("加载的数组与原始数组是否相等:", np.array_equal(arr_l, loaded_arr))
# 保存数组到文本文件 (.txt)
np.savetxt('my_array.txt', arr_l, fmt='%d') # fmt='%d' 指定保存为整数格式
print("\n数组已保存到 my_array.txt")
# 从文本文件加载数组
loaded_txt_arr = np.loadtxt('my_array.txt', dtype=int) # dtype=int 指定加载为整数类型
print("\n从 my_array.txt 加载的数组:", loaded_txt_arr)
print("从文本文件加载的数组类型:", loaded_txt_arr.dtype)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
10. 性能优势:向量化运算
NumPy 的核心优势之一是其向量化运算,可以显著提高运算效率,尤其是在处理大型数组时。
# 案例19 - 性能对比:向量化 vs 循环
size = 1000000
list_data = list(range(size))
numpy_arr = np.arange(size)
# 使用循环计算平方和 (Python 列表)
import time
start_time = time.time()
list_squared_sum = 0
for num in list_data:
list_squared_sum += num ** 2
list_time = time.time() - start_time
print("\n案例19 - 性能对比 (向量化 vs 循环):")
print("Python 列表循环计算平方和耗时: {:.4f} 秒".format(list_time))
# 使用 NumPy 向量化运算计算平方和 (NumPy 数组)
start_time = time.time()
numpy_squared_sum = np.sum(numpy_arr ** 2) # 向量化平方和运算
numpy_time = time.time() - start_time
print("NumPy 向量化运算计算平方和耗时: {:.4f} 秒".format(numpy_time))
print("NumPy 向量化运算速度是循环的约 {:.2f} 倍".format(list_time / numpy_time))
# 案例20 - 广播的性能优势
arr_m = np.random.rand(1000, 1000)
scalar_m = 2
start_time = time.time()
result_broadcast = arr_m + scalar_m # 广播运算
broadcast_time = time.time() - start_time
start_time = time.time()
result_loop = np.zeros_like(arr_m)
for i in range(arr_m.shape[0]):
for j in range(arr_m.shape[1]):
result_loop[i, j] = arr_m[i, j] + scalar_m # 循环逐元素相加
loop_time = time.time() - start_time
print("\n案例20 - 广播性能优势:")
print("广播运算耗时: {:.4f} 秒".format(broadcast_time))
print("循环逐元素相加耗时: {:.4f} 秒".format(loop_time))
print("广播运算速度是循环的约 {:.2f} 倍".format(loop_time / broadcast_time))
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
总结
这20个案例涵盖了 NumPy 最常用的功能,包括数组创建、基本操作、索引切片、形状变换、聚合函数、合并分割、广播、线性代数运算以及性能优势。通过学习和实践这些案例,你应该能够基本掌握 NumPy 的核心用法,并为后续深入学习数据分析、机器学习等领域打下坚实的基础。