聚合
当⾯对⼤量数据的时候,我们经常需要可计算数据的⼀些统计方⾯的信息,所幸numpy给我们提供了很
多好用的聚合类功能,可以让我们方便的进⾏⼀些操作。
numpy的聚合可以直接作用在数组上⾯,不需要每次都numpy.xxx调⽤。
同时⼀般如果名称相同功能也相同,相对速度比python同名功能要快。
numpy中可⽤的聚合函数如下,需要注意的是,除any和all之外,每个函数都存在⼀个NaN安全的版
本,形式是在函数名称前加nan,例如np.nansum就是sum的NaN安全版本:
- np.sum: 和
- np.prod: 积
- np.mean: 平均数
- np.std: 标准差
- np.var: ⽅差
- np.min: 最⼩值
- np.max: 最⼤值
- np.argin: 最⼩值的索引
- np.argmax: 最⼤值的索引
- np.median: 中位数
- np.oercentile: 基于元素排序的统计值
- np.any: 是否⾄少存在⼀个为真的元素
- np.all: 所有元素是否为真
适用通用函数的聚合函数
此类函数主要指的是reduce和accumulate。
- reduce: 功能同python的标准reduce⼀致,即重复执行某⼀个操作知道最后⼀个结果。
- accumulate: 计算的中间结果会被存储
# reduce
a = np.arange(100)
# 把a内所有值进⾏相加
b = np.add.reduce(a)
print("b = ", b)
# 把a内所有制相加,但相加的中间结果需要保存下来
c = np.add.accumulate(a)
print("c = \n", c)
b = 4950
c =
[ 0 1 3 6 10 15 21 28 36 45 55 66 78 91
105 120 136 153 171 190 210 231 253 276 300 325 351 378
406 435 465 496 528 561 595 630 666 703 741 780 820 861
903 946 990 1035 1081 1128 1176 1225 1275 1326 1378 1431 1485 1540
1596 1653 1711 1770 1830 1891 1953 2016 2080 2145 2211 2278 2346 2415
2485 2556 2628 2701 2775 2850 2926 3003 3081 3160 3240 3321 3403 3486
3570 3655 3741 3828 3916 4005 4095 4186 4278 4371 4465 4560 4656 4753
4851 4950]
数组值求和
numpy.sum函数和python的求和函数功能基本⼀致,但是还是有⼀些小区别:
- numpy的求和函数具有维度的概念,求和多项可以是数组
- 同时参数含义跟python的sum并不⼀致
- numpy.sum速度快⼀些
a = np.arange(100).reshape((10,10))
b = np.sum(a)
print(b)
4950
最大值和最小值
求最大值最小值:
- min:最小值
- max:最小值
a = np.random.rand(20)
print("a = \n", a)
# 调⽤pyhton的标准min
m1 = min(a)
print("最⼩值: ", m1)
# 调⽤numpy的min
m2 = np.min(a)
print("最⼩值: ", m2)
# numpy.min的简写形式,跟进a的类型会⾃动调⽤numpy.min
m3 = a.min()
print("最⼩值: ", m3)
a =
[0.23934032 0.15596611 0.85993783 0.13911453 0.03351837 0.73838562
0.21018289 0.72901198 0.94990497 0.980913 0.40451059 0.22112041
0.29087158 0.86319102 0.30870189 0.53390399 0.74920732 0.00546603
0.60973917 0.15531549]
最小值: 0.005466033221787847
最小值: 0.005466033221787847
最小值: 0.005466033221787847
多维度聚合
numpy研究的数据经常是多个维度的,这时候经常需要的操作是沿着某⼀轴进⾏操作,此时,聚合函数
都会有⼀个参数axis,用来表示需要沿着哪个轴进⾏聚合。
a = np.random.randint(100, size=(4,5))
print("a = \n", a)
# 求最⼤值,每⼀⾏
b = a.max(axis=1)
print("a每⼀⾏的最⼤值是: ", b)
# 求每⼀列的和
c = a.sum(axis=0)
print("a每⼀列的和是:", c)
a =
[[48 17 0 54 12]
[76 1 69 14 36]
[77 44 90 32 50]
[44 45 8 9 68]]
a每⼀⾏的最⼤值是: [54 76 90 68]
a每⼀列的和是: [245 107 167 109 166]
广播
对不同大小的数组进行计算的时候,需要想法对齐数组的长度,广播就是自动对齐数组长度的⼀种规
则。
广播允许对不同大小的数组进⾏操作,例如前⾯介绍的⼀个标量和⼀个数组相加,这种自动把自己编成
和对方形状⼀样然后进行操作的能力,叫广播。
a = np.zeros(5)
print("a = ", a)
# 我们可以认为是 a + 4 = array(0,0,0,0,0) + array(4,4,4,4,4)
# 此时标量4⾃动扩展成了 array(4,4,4,4,4)
b = a + 4
print("b = ", b)
a = [0. 0. 0. 0. 0.]
b = [4. 4. 4. 4. 4.]
a = np.arange(5)
print("a = ", a)
print()
b = np.arange(15).reshape((3,5))
print("b = \n", b)
print()
# 此处相当于把b按⾏扩展成了⼀个 3x5的数组,然后和a进⾏bitwise的相加
c = a + b
print("c = \n", c)
a = [0 1 2 3 4]
b =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
c =
[[ 0 2 4 6 8]
[ 5 7 9 11 13]
[10 12 14 16 18]]
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]
c = a + b
print("a = \n", a)
print()
print("b = \n", b)
print()
print("c = \n", a + b)
a =
[0 1 2]
b =
[[0]
[1]
[2]]
c =
[[0 1 2]
[1 2 3]
[2 3 4]]
广播的规则
广播必须按照⼀定规则进行,不能随便播,即便是按照规则,也不是⼀定能进行广播。
广播规则如下:
- 如果两个数组维度不相同,则小维度数组形状在最左边补上1
- 如果两数组的形状在任何一个维度上都不匹配,则数组的形状会沿着维度为1的维度扩展以匹配零位⼀个数组
- 如果两两个数组的形状在任何⼀个维度上都不匹配并且没有任何⼀个维度等于1, 则异
常。
规则1 案例
a = np.arange(15).reshape((3,5))
b = np.arange(5)
c = a + b
print("a.shape = ", a.shape)
print("a = \n", a)
print()
print("b.shape = ", b.shape)
print("b = \n", b)
print()
print("c.shape = ", c.shape)
print("c = \n", c)
a.shape = (3, 5)
a =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
b.shape = (5,)
b =
[0 1 2 3 4]
c.shape = (3, 5)
c =
[[ 0 2 4 6 8]
[ 5 7 9 11 13]
[10 12 14 16 18]]
上面例子是第一个规则的运用案例
a.shape = (3,5)
b.shape = (5,)
此时如果a, b相加,则按照广播规则1, 需要在b.shape的最左边补上1, 即:
b.shape=(5,) ==> b.shape=(1,5)
然后,可以看作再把b.shape进行第⼆次扩展:
b.shape(1,5) ==> b.shape(3,5)
广播规则2
a = np.arange(5).reshape((5,1))
b = np.arange(5)
c = a + b
print("a.shape = ", a.shape)
print("a = \n", a)
print()
print("b.shape = ", b.shape)
print("b = \n", b)
print()
print("c.shape = ", c.shape)
print("c = \n", c)
a.shape = (5, 1)
a =
[[0]
[1]
[2]
[3]
[4]]
b.shape = (5,)
b =
[0 1 2 3 4]
c.shape = (5, 5)
c =
[[0 1 2 3 4]
[1 2 3 4 5]
[2 3 4 5 6]
[3 4 5 6 7]
[4 5 6 7 8]]
上⾯例⼦按照规则2进行广播。
先观察a, b的形状
a.shape = (5, 1)
b.shape = (5, )
此时广播需要先对b进行扩展:
b.shape=(5, ) ==> (1,5)
然后跟进a和b的shape分别进行扩展:
a.shape=(5,1) ==> (5,5)
b.shape=(1,5) ==> (5,5)
不能广播的案例
a = np.arange(15).reshape((3,5))
b = np.arange(3)
print("a.shape = ", a.shape)
print("b.shape = ", b.shape)
c = a + b
a.shape = (3, 5)
b.shape = (3,)
ValueError Traceback (most recent call last)
<ipython-input-95-081747746e13> in <module>()
7 print("b.shape = ", b.shape)
8
----> 9 c = a + b
ValueError: operands could not be broadcast together with shapes (3,5) (3,)
以上案例不能进行广播。
我们观察a和b的形状
a.shape = (3,5)
b.shape = (3, )
我们如果需要广播,则按照广播的规则,需要先把b的shape进行补⾜,则按照规则1:
b.shape = (3,) ==> (1,3)
经过规则1的补齐后,a,b的形状则变成了:
a.shape = (3,5)
b.shape = (1,3)
然后按照规则2再次进⾏匹配后的结果是:
a.shape = (3,5)
b.shape = (3,3)
发现经过匹配后,还是不⼀致,匹配失败抛出异常。