目录
Numpy数组的聚合与广播
前面讲解了Numpy数组的通用函数.,但其实在这些通用函数背后,在数组的计算上是有一套规则的.这套规则称为广播,它确保了Numpy中不同维的数组之间可以计算.
除此以外本章首先将讲解其他的一些聚合通用函数,然后再讲解广播
1.聚合
前面讲过,聚合的目的就是获得数组的信息,即相关数据的概括统计值.
具体包括:均值和偏差,求和,乘积,中位数,最小值和最大值,分位数等等
numpy.sum方法
Numpy的numpy.sum方法将计算数组所有的元素的值,最终返回一个值.
np.sum(数组)
例如:
print(np.sum(array_1))
print(np.sum(array_2))
print(np.sum(array_3))
>>>
22
47
274
最大最小值
求一个数组的最大最小值,有两种方法,一个是调用ndarray对象的方法.
另外一个就是使用numpy.max和numpy.min函数
ndarray对象的max和min方法
数组名.max()
数组名.min()
例如:
array_1.max()
array_2.min()
Numpy的max和min函数
numpy.max(数组名)
munpy.min(数组名)
例如:
print(numpy.min(array_1))
print(numpy.max(array_2))
沿指定方向聚合
我们这里讲解的聚合方法,最后返回的都是对整个数组的值.
如果我们想要向numpy.add.reduce方法一样沿某一列或者某一行来聚合的时候,这个时候就可以在函数或者方法中指定轴
数组名.min(axis=指定轴)
数组名.max(axis=指定轴)
np.max(数组名,axis=指定轴)
np.min(数组名,axis=指定轴)
np.sum(数组名,axis=指定轴)
其中:
- 当x=0时,表示沿列聚合,x=1时,表示沿行聚合.
常用聚合函数
下面将讲解常用的聚合函数
Numpy并不支持对缺失值(NaN,Not a Number)的处理
因此,一般的聚合函数在遇到缺失值NaN时,就会报错
所以NaN安全版本是指当遇到缺失值时,函数就会跳过,而非报错.
具体的常用函数如下:
函数名称 | NaN安全版本 | 描述 |
---|---|---|
np.sum | np.nansum | 计算元素的和 |
np.prod | np.nanprod | 计算元素的积 |
np.mean | np.nanmean | 计算元素的平均值 |
np.std | np.nanstd | 计算元素的标准差 |
np.var | np.nanvar | 计算元素的方差 |
np.min | np.nanmin | 找出最小值 |
np.max | np.nanmax | 找出最大值 |
np.argmin | np.nanargmin | 找出最小值的索引 |
np.argmax | np.nanargmax | 找出最大值的索引 |
np.median | np.nanmedian | 计算元素的中位数 |
np.percentage | np.nanpercentage | 计算基于元素排序的统计值 |
np.any | 无 | 验证数组中是否有一个元素 |
np.all | 无 | 验证所有元素是否为某个值 |
2.广播
上一届讲解了Numpy如何通过通用函数的享量化操作来减少缓慢的Python原生循环.另外一种向量化操作的方法就是利用Numpy的广播功能.
简单的理解广播就是用于不同形状数组的二进制通用函数(加减乘除,内积外积等)的一组规则.
用于确保低维数组和高维数组或者两个不同形状的数组计算时候能够正确计算.
广播的介绍
在讲解广播的规则前,举几个例子来介绍下广播.
我们前面提到过,同样大小的数组,二进制操作就是相应元素逐个计算
import numpy as np
array_1=np.array([0,1,2,3])
array_2=np.array([1,1,1,1])
print(array_1+array_2)
>>>
[1,2,3,4]
如果我们用一个低维数组和高维数组进行操作
import numpy as np
array_1=np.array([0,1,2,3])
print(array_1+1)
>>>
[1,2,3,4]
发现得到了和第一个同维数组相加相同的结果.
我们可以理解为,Numpy将一维数组(不妨把数字看成一维数组)进行了扩展
即把1扩展为[1,1,1,1],使其与高维数组同形,然后可以进行计算.
同样的道理,我们在举一个一维数组和二维数组相加的例子.
import numpy as np
array_1=np.array([1,1,1])
array_2=np.arange(1,10).reshape(3,3)
print(array_1)
print(array_2)
print(array_1+array_2)
>>>
[1 1 1]
[[1 2 3]
[4 5 6]
[7 8 9]]
[[ 2 3 4]
[ 5 6 7]
[ 8 9 10]]
发现将array_1沿第二个维度进行了广播
再给出一个复杂的例子,两个数组都进行了广播以达到同样的大小
import numpy as np
array_1=np.array([1,2,3])
array_2=np.array([1,2,3])[:,np.newaxis]
print(array_1)
print(array_2)
print(array_1+array_2)
>>>
[1 2 3]
[[1]
[2]
[3]]
[[2 3 4]
[3 4 5]
[4 5 6]]
可以发现,array_1沿第二个方向进行了扩展,array_2沿第一个方向进行了扩展,最后两者都扩展为(3,3)形状的数组,进行计算
广播的规则
Numpy的广播遵循一组严格的规则,只有符合规则的不同形状的数组才能进行计算,否则就会报错.
具体规则如下:
- 如果两个数组的维度数不同,那么小维度数组的形状将会在最左边补1
- 如果两个数组的形状在任何一个维度上不匹配,那么数组的形状会沿着维度为1的维度扩展以匹配另外一个数组的形状
- 如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常
下面就将举几个例子来理解这些规则
import numpy as np
array_1=np.arang(3) #array_1是一个一维数组大小为(3,)
array_2=np.ones((2,3)) #array_2是一个二维数组,大小为(2,3)
print(array_1+array_2)
#根据规则1,array_1维度更小,将会在左边补1,即将array_1升维成一个(1,3)的二维数组
#根据规则2,array_1在第一个维度上为1,所以将array_1扩展为(2,3)的二维数组
>>>
[[1. 2. 3.]
[1. 2. 3.]]
import numpy as np
array_1=np.arange(3)
array_2=np.arange(3).reshape((3,1))
print(array_1+array_2)
#根据规则1,array_1维度较小,因此在左边补1,升维成(1,3)
#根据规则2,array_1第一个维度的大小为1,因此扩充第一个维度成(3,3)
#根据规则2,array_2第二个维度的大小为2,因此扩充第二个维度成(3,3)
>>>
[[0 1 2]
[1 2 3]
[2 3 4]]
import numpy as np
array_1=np.arange(3)
array_2=np.ones((3,2))
print(array_1+array_2)
#根据规则1,array_1维度较小,因此在左边补1,升维称(1,3)
#根据规则2,array_1第一个维度大小为1,因此扩充第一个维度成(3,3)
#由于两个形状不匹配,因此报错
>>>
Traceback (most recent call last):
File "c:\Users\22321\Desktop\Python练习\数据分析练习\Numpy练习.py", line 177, in <module>
print(array_1+array_2)
ValueError: operands could not be broadcast together with shapes (3,) (3,2)
因此这种情况下,如果我们还希望让两个数组相加,那么就要改变第一个数组的形状
print(array_1[:,np.newaxis]+array_2)
>>>
[[1. 1.]
[2. 2.]
[3. 3.]]
广播的实际运用
广播操作是整个Python数据分析的关键,下面将给出几个广播运用的实际例子
数组的归一化
归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。
即抛却一组数据本身的特征,研究数据间的相对关系.
例如:==观察一组数据的离散情况
import numpy as np
array=np.random.randint((10,3))
mean=array.mean()
array_center=array-mean #进行了广播操作
print(array)
print(array_center)
print(array_center.mean())
>>>
[[6 9 8]
[9 7 5]
[5 1 3]
[6 2 2]
[1 8 4]
[9 5 3]
[3 5 4]
[6 3 6]
[9 5 1]
[9 5 6]]
[[ 0.83333333 3.83333333 2.83333333]
[ 3.83333333 1.83333333 -0.16666667]
[-0.16666667 -4.16666667 -2.16666667]
[ 0.83333333 -3.16666667 -3.16666667]
[-4.16666667 2.83333333 -1.16666667]
[ 3.83333333 -0.16666667 -2.16666667]
[-2.16666667 -0.16666667 -1.16666667]
[ 0.83333333 -2.16666667 0.83333333]
[ 3.83333333 -0.16666667 -4.16666667]
[ 3.83333333 -0.16666667 0.83333333]]
-2.9605947323337506e-16
最后发现,在机器精度范围内,均值为0.
从上面的数组中,能够看到生成的随机数组关于均值的绝对偏差,如果再除以平均值取绝对值,就得到了相对偏差
print(np.abs(array_center/array.mean()))
>>>
[[0.19463087 0.81208054 0.00671141]
[0.19463087 0.39597315 0.39597315]
[0.79865772 0.59731544 0.39597315]
[0.61073826 0.81208054 0.20805369]
[0.61073826 0.61073826 0.40939597]
[0.00671141 0.79865772 0.39597315]
[0.39597315 0.40939597 0.61073826]
[0.79865772 0.40939597 0.79865772]
[0.81208054 0.39597315 0.79865772]
[0.00671141 0.81208054 0.20805369]]
绘制二维图像
二维图像本质上是二维平面的到三维空间的映射.
即xoy面上一个点(x,y),经过函数f(x,y)计算之后,得到在z轴上的坐标z=f(x,y).
点(x,y)又是面xoy上任意一个点,因此二维函数本质上就是二维平面到三维空间的映射.
所以我们在绘制二维图像的时候,就需要广播来计算z的值(matplotlib详见matplotlib学习专栏)
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,5,50)
y=np.linspace(0,5,50)
z=np.sin(x)**10+np.cos(10+x*y)*np.cos(x) #z的值的计算运用了广播
plt.imshow(z,origin='lower',extent=[0,5,0,5],camp='viridis')
plt.colorbar()
plt.show()
结果如下:
又是面xoy上任意一个点,因此二维函数本质上就是二维平面到三维空间的映射.
所以我们在绘制二维图像的时候,就需要广播来计算z的值(matplotlib详见matplotlib学习专栏)
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,5,50)
y=np.linspace(0,5,50)
z=np.sin(x)**10+np.cos(10+x*y)*np.cos(x) #z的值的计算运用了广播
plt.imshow(z,origin='lower',extent=[0,5,0,5],camp='viridis')
plt.colorbar()
plt.show()
结果如下: