numpy的广播(broadcasting)机制

版权声明:站在巨人的肩膀上学习。 https://blog.csdn.net/zgcr654321/article/details/83387337

什么是广播:

Numpy的广播既是在2个不同的矩阵运算过程中,Numpy将较小的数组拉伸成较大数组的形状(shape),较小维度的数组会被广播到另一个数组的相应维度上去,这就使得两个不同形状(但也有基本要求,不是任何维度都可以广播)的数组也可以进行运算。

如:

import numpy as np

a = np.array([1.0, 2.0, 3.0])
b = 2.0
print(a, a.shape)
print(b)
print(a * b)

运行结果如下:

[1. 2. 3.] (3,)
2.0
[2. 4. 6.]

广播原则:

如果满足以下规则,可以进行广播:

维度较小的数组会在前面追加一个长度为 1 的维度;

输出数组的每个维度的大小是输入数组该维度大小的最大值;

如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则在计算中可它;

如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。

按照上述规则修改数组后,如果还满足下面的要求,那么称为输入数组是可广播的:

输入数组和输出数组拥有相同形状;

输入数组和输出数组的维数相同,且各个维上的数值相同(数值就是我们通常说的m行n列的m和n),或者数值不同但数值为 1;

对上面的规则的通俗说法:

首先检查两个变量维数是否相同,若不同,对维数少的补一。维数不是指n行d列中的n和d的值,对于一般的矩阵维数就是2。如一个两维的矩阵(n,d)和一个一维的数组(m,)相乘,补一操作就是将那个一维的数组变为(1,m),补一总是在shape数组的开始位置补一;

输出数组是输入数组各维度(轴)的最大值。如(2,3)和(3,)相乘,首先做第一步的维度调整,修正为(2,3)和(1,3)。那么第一维最大是在2和1中选2,第二维最大值是在3和3中选3。那么输出数组维度是(2,3);

扫描二维码关注公众号,回复: 3759915 查看本文章

检查输入数组各维的数和输出数组各维的关系,要么相等,要么为一(注意是每个维度都要满足要么相等要么为1)。如上面的例子中输入数组(2,3)和输出数组(2,3)在各维上都是相等的,而(1,3)和(2,3)虽然第一维不相等,但是却等于1,这也是可以计算的。再举一个反例(2,4)(3,),先做维度调整,变为(2,4)和(1,3),在计算输出数组的维度为(2,4),最后做第三步输入数组(2,4)和输出数组(2,4)相等,但输入数组(1,3)和输出数组(2,4)的第二维不相等也不等于1,所以计算失败。

经过上面的步骤,可以认为输入的两个数组各维的数要么相等要么等于1。对于等于1的维度开始复制增补。如(1,3)和(3,1)的输出是(3,3)。对于(1,3)要对每一行复制,最终变为(3,3),例如[[2,3,4]]变为[[2,3,4],[2,3,4],[2,3,4]]。对于(3,1)要对每一列复制,最终变为(3,3),例如[[2],[3],[4]]]变为[[2,2,2],[3,3,3],[4,4,4]]。总之哪一维为1就对哪一维复制增补,直到输入数组的形状(shape)和输出数组的形状相同。完成了这一步,两个数组的shape就完全相同,这时候就可以执行普通运算了。

如:

import numpy as np

x = np.arange(4)
xx = x.reshape(4, 1)
y = np.ones(5)
z = np.ones((3, 4))

print(x, x.shape)
print(y, y.shape)
# print(x + y)
# 如果运行print(x + y)会出现下面的错误提示,因为x是1维数组,y也是一维数组,但x有4个元素,而y有5个元素,不满足广播机制的要求
# <type 'exceptions.ValueError'>: shape mismatch: objects cannot be broadcast to a single shape
# xx变成了4行一列的矩阵,每个元素是原来一维数组的单个元素
print(xx, xx.shape)
print(y, y.shape)
print(xx + y, (xx + y).shape)
# xx现在是4行1列,y是一维数组有5个元素,即(4,1)和(5,)相乘,根据广播原则,y要在所有维度前追加一个长度为1的维度,变成(1,5)
# 那么输出数组就应该是两个输入的数组中每个维度上的最大值,即(4,1)和(1,5)同样维度比较,取最大值,应该是(4,5)
# 检查输入数组各维的数值和输出数组各维的数值的关系,要么相等要么是1
# 输入数组(4,1)和(1,5),输出数组是(4,5),那么对(4,1),其第一个维度数值与(4,5)相等,第二个维度数值等于1,满足,对(1,5)也这么检查,也满足
# 对输入数组中等于1的维度开始复制增补
# 对(4,1)按列增补到(4,5),对(1,5)按行增补到(4,5),然后相加

print(x, x.shape)
print(z, z.shape)
print(x + z, (x + z).shape)
# x是(4,),z是(3,4),那么在x前追加一个长度为1的维度,变成(1,4)
# 输出数组就是(1,4)和(3,4)上每个维度中数值的最大值,应该是(3,4)
# 检查输入数组各维的数值和输出数组各维的数值的关系,要么相等要么是1
# (1,4)和(3,4)与输出数组(3,4)满足上面的要求
# 对(1,4)按行增补到(3,4),然后相加

上面代码中包含两个例子:

xx+y:

xx是(4,1)矩阵,值为

[[0]
 [1]
 [2]
 [3]] (4, 1)

y是一维数组(5,),值为

[1. 1. 1. 1. 1.] (5,)

根据广播原则,y要在所有维度前追加一个长度为1的维度,变成(1,5),输出数组就应该是两个输入的数组中每个维度上的最大值:

即(4,1)和(1,5)同样维度比较,取最大值,应该是(4,5)

检查输入数组各维的数值和输出数组各维的数值的关系,要么相等要么是1:

输入数组(4,1)和(1,5),输出数组是(4,5),那么对(4,1),其第一个维度数值与(4,5)相等,第二个维度数值等于1,满足,对(1,5)也这么检查,也满足。

对输入数组中等于1的维度开始复制增补:
# 对(4,1)按列增补到(4,5),对(1,5)按行增补到(4,5),然后相加,就可以得到结果

[[1. 1. 1. 1. 1.]
 [2. 2. 2. 2. 2.]
 [3. 3. 3. 3. 3.]
 [4. 4. 4. 4. 4.]] (4, 5)

x+z:

x是(4,),z是(3,4),那么在x前追加一个长度为1的维度,变成(1,4);

输出数组就是(1,4)和(3,4)上每个维度中数值的最大值,应该是(3,4);

检查输入数组各维的数值和输出数组各维的数值的关系,要么相等要么是1。(1,4)和(3,4)与输出数组(3,4)满足上面的要求;

对(1,4)按行增补到(3,4),然后相加,结果为

[[1. 2. 3. 4.]
 [1. 2. 3. 4.]
 [1. 2. 3. 4.]] (3, 4)

运行结果如下:

[0 1 2 3] (4,)
[1. 1. 1. 1. 1.] (5,)
[[0]
 [1]
 [2]
 [3]] (4, 1)
[1. 1. 1. 1. 1.] (5,)
[[1. 1. 1. 1. 1.]
 [2. 2. 2. 2. 2.]
 [3. 3. 3. 3. 3.]
 [4. 4. 4. 4. 4.]] (4, 5)
[0 1 2 3] (4,)
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]] (3, 4)
[[1. 2. 3. 4.]
 [1. 2. 3. 4.]
 [1. 2. 3. 4.]] (3, 4)

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/zgcr654321/article/details/83387337
今日推荐