【numpy笔记_5】数组的算数运算与广播机制

算数运算

与常规的list对象不同,numpy支持把整个数组带入算数运算。

之前提过,array对象往往要求所有元素保持统一的数据类型,因此numpy的运算能以数组为单位,而不用将元素提出来。
这也是numpy能够胜任高效运算的原因之一。

来看几个例子:

import numpy as np
arr = np.arange(1,10).reshape(3, 3)
array_1 = arr > 7   # 条件比较,返回bool
array_2 = arr * 0.3   # 加减乘除运算

arrs = np.arange(11,20).reshape(3,3)
array_3 = arrs / arr   # 数组间的运算

print(array_1)
print('* '*20)
print(array_2)
print('* '*20)
print(array_3)
# 运行结果:
[[False False False]
 [False False False]
 [False  True  True]]
* * * * * * * * * * * * * * * * * * * * 
[[0.3 0.6 0.9]
 [1.2 1.5 1.8]
 [2.1 2.4 2.7]]
* * * * * * * * * * * * * * * * * * * * 
[[11.          6.          4.33333333]
 [ 3.5         3.          2.66666667]
 [ 2.42857143  2.25        2.11111111]]

可以看到,numpy甚至支持两个数组对象的算数运算。我们因此得到结论:
在numpy中,参与算术运算的单位可以是数组(“可以”不是“只能”)。

数组和数字的计算没什么好说的。
而数组与数组的运算,我们发现上面的例子中,两个运算的数组结构相同。这很好理解,两组的元素呈一一对应关系,这是映射

那如果一对结构不同的数组呢?这就是我们要讲的广播机制


广播机制

“广播”,顾名思义有传递、向外扩散的意思。

numpy的广播机制也是如此,指两个不同shape的数组,在它们的shape满足一定条件时,可进行广播运算。这时,两个数组的元素按照一定规则扩散开来运算,并得到一个新的数组。

借用经典的描述就是,numpy中的广播机制旨在解决不同形状数组之间的算数运算问题
我们来看数组运算的几个例子,观察广播机制是如何运作的:

import numpy as np
arr_2d_3x3 = np.arange(1,10).reshape(3, 3)   # 3*3
arr_1d_3 = np.arange(1,4)   # 3个元素的一维数组
arr_1d_4 = np.arange(1,5)   # 4个元素

array_jia = arr_2d_3x3 + arr_1d_3   # 3*3 与 3个元素 运算(拿拼音代替了..)
array_jian = arr_2d_3x3 - arr_1d_4   # 3*3 与 4个元素 运算

print(arr_2d_3x3)
print('- '*5)
print(arr_1d_3)
print(arr_1d_4)
print('* '*20)
print(array_jia)
print('* '*20)
print(array_jian)
# 运行结果:
[[1 2 3]
 [4 5 6]
 [7 8 9]]   # arr_2d_3x3
- - - - - 
[1 2 3]   # arr_1d_3
[1 2 3 4]   # arr_1d_4
* * * * * * * * * * * * * * * * * * * * 
[[ 2  4  6]
 [ 5  7  9]
 [ 8 10 12]]   # array_jia,3*3 与 3个元素 运算
* * * * * * * * * * * * * * * * * * * * 
ValueError: operands could not be broadcast together with shapes (3,3) (4,)    # array_jian,3*3 与 4个元素 运算

可以看到,两个数组在列数(个数)相同、行数(长短)不同时,“较短”的数组对“较长”的数组向下做了传播式的运算,这便是"广播机制"叫法的由来。而列数不同的数组就报错了,便不能广播。
到这还没完,再看一组例子:

import numpy as np
arr_2d_3x3 = np.arange(1,10).reshape(3, 3)   # 3*3
arr_2d_1x3 = np.arange(1,4).reshape(1, 3)   # 1*3
arr_2d_3x1 = np.arange(1,4).reshape(3, 1)   # 3*1
array_jia = arr_2d_3x3 + arr_2d_1x3   # 3*3 与 1*3 运算
array_jian = arr_2d_3x3 - arr_2d_3x1   # 3*3 与 3*1 运算

print(arr_2d_3x3)
print('- '*5)
print(arr_2d_1x3)
print('- '*5)
print(arr_2d_3x1)
print('* '*20)
print(array_jia)
print('* '*20)
print(array_jian)
# 运行结果:
[[1 2 3]
 [4 5 6]
 [7 8 9]]   # 3*3
- - - - - 
[[1 2 3]]   # 1*3
- - - - - 
[[1]
 [2]
 [3]]   # 3*1
* * * * * * * * * * * * * * * * * * * * 
[[ 2  4  6]
 [ 5  7  9]
 [ 8 10 12]]   # 3*3 与 1*3 运算
* * * * * * * * * * * * * * * * * * * * 
[[0 1 2]
 [2 3 4]
 [4 5 6]]   # 3*3 与 3*1 运算

arr_2d_3x3 = np.arange(1,10).reshape(3, 3)   # 3*3
arr_2d_1x3 = np.arange(1,7).reshape(2, 3)   # 2*3
array_jia = arr_2d_3x3 + arr_2d_1x3   # 3*3 与 2*3 运算
print(array_jia)
# 运行结果:
ValueError: operands could not be broadcast together with shapes (3,3) (2,3) 

通过上面第一个例子,很明显numpy在对两个方向不一致的数组进行运算时,基于“较短”数组的shape,选择运算规则是向行扩散还是列扩散。
用大白话说就是,相对于大数组,小数组行、列的饱和度。即:

  • 列饱和、行缺失则广播行补充;
  • 行饱和、列缺失则广播列补充。

无论如何,只要行/列有一个饱和的情况下,就将不饱和的地方广播至饱和

而第二个例子可能你也感觉到了,3x3 和 2x3 这种形状好像根本没法广播,因为小数组拿来广播的元素是不唯一的。

是的,就是这么好理解。

可能你想问,那3d及以上的数组怎么广播呢?

其实,我们已经知道高维数组(体)由多个2维数组(面)组成。
所以你可能知道了,无非就是对多个“面”逐一广播而已。
就像这样:

import numpy as np
arr_2d_3x3 = np.arange(1,13).reshape(2, 3, 2)   # 3*3
arr_2d_3x1 = np.arange(1,4).reshape(3,1)
array_jia = arr_2d_3x3 + arr_2d_3x1   # 3*3 与 3*1 运算

print(arr_2d_3x3)
print('- '*5)
print(arr_2d_3x1)
print('* '*20)
print(array_jia)
# 运行结果:
[[[ 1  2]
  [ 3  4]
  [ 5  6]]

 [[ 7  8]
  [ 9 10]
  [11 12]]]
- - - - - 
[[1]
 [2]
 [3]]   # 这是多行一列,一行多列就不举例了
* * * * * * * * * * * * * * * * * * * * 
[[[ 2  3]
  [ 5  6]
  [ 8  9]]   # 先广播第一块

 [[ 8  9]
  [11 12]
  [14 15]]]   # 再广播第二块

最后,我们总结一下广播机制:

  • 广播机制,指两个数组间的推广运算;
  • 广播对shape有一定要求。相对于大数组,小数组的行/列必须有一处饱和,且另一处唯一。即shape(1, n)shape(n,1)
  • array对象和数字直接运算(object + 1),就是numpy广播机制的体现。
  • 用于广播的小数组,必须是单个数字或二维(行、列)。
  • 广播的本质是一种算数运算,适用于加减乘除及其他所有的运算方式。


    广播机制.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容