【AI学习——NumPy入门】NumPy广播机制详解+代码示例
NumPy是Python数据分析和AI学习的基础库,核心优势是高效处理多维数组(ndarray)。本文针对初学者,梳理NumPy核心基础:数组创建、索引、广播机制(重点)、线性代数运算,全程搭配简洁代码示例,帮你快速上手实操。数组创建:重点掌握np.array()、np.zeros()、np.ones()、np.arange()、np.random.rand(),满足日常开发需求数组索引:二维数组
目录
前言:
NumPy是Python数据分析和AI学习的基础库,核心优势是高效处理多维数组(ndarray)。本文针对初学者,梳理NumPy核心基础:数组创建、索引、广播机制(重点)、线性代数运算,全程搭配简洁代码示例,帮你快速上手实操。
一、先搞懂:NumPy是什么?
NumPy(Numerical Python)是Python的数值计算库,专门解决数组运算问题。相比Python原生列表,它的优势在于:
-
存储更高效,占用内存少
-
运算速度快(底层C语言实现,避开Python解释器开销)
-
支持多维数组和广播、线性代数等高级运算
安装(已安装可跳过):
# 命令行安装
pip install numpy
# 安装验证(若安装成功,将返回已安装的版本号)
python -c "import numpy; print(numpy.__version__)"
# 使用时导入库(简写为np)
import numpy as np
二、核心重点:NumPy 核心功能详解
2.1 NumPy数组(ndarray)创建
NumPy的核心是ndarray对象,常用创建方法有3种,直接上代码+说明:
import numpy as np
# 1. 从Python列表或元组转换(最常用)
List1 = [1,2,3,4]
arr1 = np.array(List1) # 一维数组
print("一维数组:\n", arr1) # 输出:[1 2 3 4]
List2 = [[1,2],[3,4]]
arr2 = np.array(List2) # 二维数组(矩阵)
print("二维数组:\n", arr2) # 输出:[[1 2],[3 4]]
# 2. 快速创建特殊数组(避免手动写列表)
arr_zeros = np.zeros((2,3)) # 2行3列的全0数组
arr_ones = np.ones((3,2)) # 3行2列的全1数组
arr_full = np.full((2,2), 5)# 2行2列的全5数组
arr_range = np.arange(1,10,2)# 从1到9,步长2:[1 3 5 7 9]
arr_lin = np.linspace(0,1,5)# 0到1之间均匀取5个数:[0. 0.25 0.5 0.75 1. ]
# 3. 创建随机数组
arr_rand = np.random.rand(2,2) # 0-1之间的2行2列随机数
arr_randn = np.random.randn(2,2) # 符合正态分布的2行2列随机数
# 小贴士:可以使用shape属性查看数组维度(行×列),dtype查看数据类型。
# 例:print(arr2.shape) → (2,2),print(arr2.dtype) → int64
2.2 NumPy数组索引(取值/切片)
索引就是从数组中获取元素,和Python列表类似,但支持多维索引,重点看二维数组(矩阵)的操作:
import numpy as np
# 先创建一个示例二维数组
arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
print("原始数组:\n", arr)
# 1. 一维数组索引(和列表完全一致)
arr1 = np.array([10,20,30])
print("一维数组第2个元素:", arr1[1]) # 索引从0开始,输出20
print("一维数组切片(1到末尾):", arr1[1:]) # 输出[20 30]
# 2. 二维数组索引(行索引, 列索引)
print("第2行第3列元素:", arr[1,2]) # 输出6(第2行索引1,第3列索引2)
print("第1行所有元素:", arr[0,:]) # 输出[1 2 3](:表示取所有列)
print("第3列所有元素:", arr[:,2]) # 输出[3 6 9](:表示取所有行)
# 3. 二维数组切片(范围取值)
print("前2行,前2列元素:\n", arr[:2,:2]) # 输出[[1 2],[4 5]]
print("第2-3行,第1-2列元素:\n", arr[1:3,0:2]) # 输出[[4 5],[7 8]]
# 4. 布尔索引(条件筛选,实用!)
print("数组中大于5的元素:", arr[arr>5]) # 输出[6 7 8 9]
# 5. 混用
result = arr[1:3,0:2][arr[1:3,0:2] > 5]
print("第2-3行,第1-2列元素中大于5的元素:", result)
2.3 重点难点:NumPy广播机制详解
广播是NumPy最强大的特性之一,简单说:当两个数组形状不同时,NumPy会自动调整它们的形状,使其可以进行元素级运算(如加减乘除),不用手动扩展数组,极大简化代码。
2.3.1 广播的核心规则(必记)
-
维度补1:先比较两个数组的维度,维度少的数组,在前面补1(比如二维数组(2,3)和三维数组(4,2,3)比较时,二维数组补成(1,2,3))
-
逐维兼容:对于补维后的两个数组,逐维度比较形状:要么维度大小相等,要么其中一个为1;只要有一个维度不满足,就会报错即广播失败
-
逻辑扩展:满足规则后,运算时将形状为1的维度,扩展成和另一个数组相同的大小(仅逻辑扩展,不占用实际内存,所以高效)
一言以蔽之:先补维度,再看维度是否兼容,兼容就扩展维度为1的轴,最后逐元素运算。
2.3.2 常见广播示例(结合代码理解)
-
一维数组的广播

示例代码:
import numpy as np
# 定义一个数组(形状为(4, 3))
arr1 = np.sort(np.array([0,1,2,3]*3)).reshape(4,3)
# 定义第二个数组(形状为(1, 3),对应一维数组在轴0上的广播)
arr2 = np.array([[1, 2, 3]])
# 直接相加(NumPy自动广播arr2到(4, 3)形状)
result = arr1 + arr2
print("第一个数组:")
print(arr1)
print("\n第二个数组:")
print(arr2)
print("\n广播相加的结果:")
print(result)
运行结果如下:
第一个数组:
[[0 0 0]
[1 1 1]
[2 2 2]
[3 3 3]]
第二个数组:
[[1 2 3]]
广播相加的结果:
[[1 2 3]
[2 3 4]
[3 4 5]
[4 5 6]]
分析底层逻辑:
补维度:arr1形状 (4,3),arr2形状 (1,3)(维度数相同,无需补 1);
逐维兼容:轴0(4 vs 1)兼容,轴1(3 vs 3)兼容;
逻辑扩展:arr2的轴 0(大小 1)扩展为4(虚拟复制 4 行),变成和arr1一样的 (4,3);
通俗总结:当两个数组 “列数一样、行数不一样(其中一个行数为1)” 时,NumPy会自动把 “行数为1的数组” 复制多份,补成和另一个数组一样的行数,然后再计算。
-
二维数组的广播

示例代码:
import numpy as np
# 定义第一个数组(形状(4,3),对应图中左侧数组)
arr1 = np.sort(np.array([0,1,2,3]*3)).reshape(4,3)
# 定义第二个数组(形状(4,1),对应图中中间的二维数组)
arr2 = np.array([
[1],
[2],
[3],
[4]
])
# 广播相加(NumPy自动扩展arr2的列维度)
result = arr1 + arr2
print("数组1(4行3列):")
print(arr1)
print("\n数组2(4行1列):")
print(arr2)
print("\n广播相加结果(4行3列):")
print(result)
运行结果:
数组1(4行3列):
[[0 0 0]
[1 1 1]
[2 2 2]
[3 3 3]]
数组2(4行1列):
[[1]
[2]
[3]
[4]]
广播相加结果(4行3列):
[[1 1 1]
[3 3 3]
[5 5 5]
[7 7 7]]
分析底层逻辑:
补维度:arr1形状 (4,3),arr2形状 (4,1)(维度数相同,无需补 1);
逐维兼容:轴0(4 vs 4)兼容,轴1(3 vs 1)兼容;
逻辑扩展:arr2的轴1(大小 1)扩展为3(虚拟复制3列),变成和arr1一样的 (4,3);
通俗总结:当数组 “行数相同、列数不同(其中一个列数为1)” 时,NumPy会自动把 “列数为1的数组” 的列复制多份,补成和另一个数组一样的列数,再计算。
-
三维数组的广播

示例代码
import numpy as np
# 定义三维数组arr1(形状(3,4,2),对应图中左侧数组)
# 结构:3个"层",每个层是4行2列的二维数组
arr1 = np.array([0,1,2,3,4,5,6,7]*3).reshape(3,4,2)
# 定义待广播的数组arr2(形状(4,2),对应图中中间数组)
arr2 = np.array([0,1,2,3,4,5,6,7]).reshape(4,2)
# 三维广播相加
arr3 = arr1 + arr2
# 打印结果验证
print("arr1的形状:", arr1.shape)
print("arr1的内容:\n",arr1)
print("\narr2的形状:", arr2.shape)
print("arr2的内容:\n",arr2)
print("\n广播相加后arr3的形状:", arr3.shape)
print("arr3的内容:\n",arr3)
运行结果:
arr1的形状: (3, 4, 2)
arr1的内容:
[[[0 1]
[2 3]
[4 5]
[6 7]]
[[0 1]
[2 3]
[4 5]
[6 7]]
[[0 1]
[2 3]
[4 5]
[6 7]]]
arr2的形状: (4, 2)
arr2的内容:
[[0 1]
[2 3]
[4 5]
[6 7]]
广播相加后arr3的形状: (3, 4, 2)
arr3的内容:
[[[ 0 2]
[ 4 6]
[ 8 10]
[12 14]]
[[ 0 2]
[ 4 6]
[ 8 10]
[12 14]]
[[ 0 2]
[ 4 6]
[ 8 10]
[12 14]]]
分析底层逻辑:
补维度:arr1形状 (3,4,2)(3维),arr2形状 (4,2)(2维)→ 给arr2左侧补1,变成 (1,4,2);
逐维兼容:轴0(3 vs 1)兼容,轴1(4 vs 4)兼容,轴2(2 vs 2)兼容;
逻辑扩展:arr2的轴0(大小 1)扩展为3(虚拟复制 3 层),变成和arr1一样的 (3,4,2);
通俗总结:三维数组的 “层维度”(轴0)如果不匹配(其中一个层数为1),NumPy会自动把 “层数为1的数组” 的层复制多份,补成和另一个数组一样的层数,再计算。
2.3.3 标量与数组的广播(最常用)
标量即 “单个数值”(比如5、10.2、-3),和数组相对。在NumPy中,标量没有 “维度” 或 “形状” 的概念,可看作 “形状为 () 的空维度对象”。
标量与数组的广播,就是NumPy自动把单个数值 “变形成” 和数组一模一样的形状,然后给数组每个元素都做相同的运算,既简洁又高效。
示例1:一维数组+标量
arr1 = np.array([1, 2, 3]) # 形状(3,),一维数组(1行3列)
scalar = 10 # 标量
result1 = arr1 + scalar
print("一维数组+标量结果:", result1)
# 输出:一维数组+标量结果: [11 12 13]
示例2:二维数组 + 标量(更常用)
arr2 = np.array([[1, 2], [3, 4]]) # 形状(2,2),二维数组(2行2列)
result2 = arr2 * 2 # 标量2,乘法运算
print("\n二维数组×标量结果:\n", result2)
# 输出:
# [[2 4]
# [6 8]]
实例3:三维数组 + 标量(同理)
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 形状(2,2,2)
result3 = arr3 - 1 # 标量1,减法运算
print("\n三维数组-标量结果:\n", result3)
# 输出:
# [[[0 1]
# [2 3]]
# [[4 5]
# [6 7]]]
标量广播仅适用于元素级运算(+、-、×、/、//、% 等),不适用于矩阵乘法(矩阵乘法需要二维数组,标量无法参与)。
2.3.4 广播失败的场景
示例代码:
# 数组1:2行2列
arr1 = np.array([[1,2],[3,4]])
# 数组2:1行3列
arr2 = np.array([[1,2,3]])
# 尝试广播相加
try:
result = arr1 + arr2
except ValueError as e:
print("广播失败原因:", e)
运行结果:
广播失败原因: operands could not be broadcast together with shapes (2,2) (1,3)
分析失败逻辑:
补维度:arr1(2,2),arr2(1,3)(维度数相同,无需补1);
逐维兼容:轴0(2 vs 1)兼容,但轴1(2 vs 3)既不相等、也没有一个为1 → 不兼容,广播失败;
通俗总结:不是所有 “行数 / 列数不一样” 都能广播,必须满足「其中一个维度为1」,否则直接报错。
2.4 NumPy线性代数运算
在AI学习中经常用到矩阵乘法、求逆、行列式等线性代数操作,NumPy的linalg模块提供了完整支持,下面使用实例代码介绍常用操作:
import numpy as np
from numpy.linalg import inv, det, eig # 导入常用线性代数函数
# 1. 矩阵乘法(注意:不是元素级乘法,用@或dot())
A = np.array([[1,2],[3,4]]) # 2×2矩阵
B = np.array([[5,6],[7,8]]) # 2×2矩阵
# 方法1:用@符号(Python 3.5+支持,推荐)
mat_mul1 = A @ B
# 方法2:用dot()函数
mat_mul2 = A.dot(B)
print("矩阵乘法结果:\n", mat_mul1)
# 输出:[[19 22],[43 50]](计算规则:行×列求和)
# 2. 求矩阵的逆(仅方阵且可逆时可用)
A_inv = inv(A)
print("A的逆矩阵:\n", A_inv)
# 验证:A × A逆 = 单位矩阵(对角线为1,其他为0)
print("A×A逆验证:\n", A @ A_inv)
# 3. 求矩阵的行列式(仅方阵)
A_det = det(A)
print("A的行列式:", A_det) # 输出-2.0
# 4. 求特征值和特征向量(AI中PCA、神经网络常用)
eigenvalues, eigenvectors = eig(A)
print("A的特征值:", eigenvalues)
print("A的特征向量:\n", eigenvectors)
# 5. 其他常用操作
C = np.array([[1,2,3],[4,5,6]]) # 2×3矩阵
print("矩阵转置:\n", C.T) # 转置(行变列,列变行),输出3×2矩阵
print("矩阵的秩:", np.linalg.matrix_rank(C)) # 输出2
三、总结:初学者必掌握的核心要点
-
数组创建:重点掌握np.array()、np.zeros()、np.ones()、np.arange()、np.random.rand(),满足日常开发需求
-
数组索引:二维数组的“行,列”索引和切片是基础,布尔索引是实用技巧
-
广播机制:记住3个核心规则,多练示例,避免手动扩展数组的冗余操作
-
线性代数:区分“矩阵乘法(@)”和“元素级乘法(*)”,掌握逆、行列式、特征值的基本用法
建议:把文中代码逐行复制到Python环境中运行,修改参数观察结果(比如改数组形状、换运算符号),比单纯看文字理解更快。如果遇到问题,欢迎在评论区交流~
参考资料:NumPy官方文档(https://numpy.org/doc/stable/)
更多推荐

所有评论(0)