这里是numpy库学习笔记之数学和统计方法,收到请回答。
基本数组统计方法
sum、mean、标准差std函数
可以通过numpy库自带的数学函数对整个数组或者某个轴向的数据进行统计计算。sum、mean以及标准差std等聚合计算(aggregation,通常叫做约简(reduction))。
这里,我们用一个正态分布的随机矩阵,统计出它的基本统计量(原文的翻译是聚类分析,但是好像不是那么一回事):
In [177]: arr = np.random.randn(5, 4)
In [178]: arr
Out[178]:
array([[ 2.1695, -0.1149, 2.0037, 0.0296],
[ 0.7953, 0.1181, -0.7485, 0.585 ],
[ 0.1527, -1.5657, -0.5625, -0.0327],
[-0.929 , -0.4826, -0.0363, 1.0954],
[ 0.9809, -0.5895, 1.5817, -0.5287]])
In [179]: arr.mean()
Out[179]: 0.19607051119998253
In [180]: np.mean(arr)
Out[180]: 0.19607051119998253
In [181]: arr.sum()
Out[181]: 3.9214102239996507
从上文中我们可以看到,mean函数既可以当作数组的实例方法调用,也可以当作顶级numpy函数使用,不过就写法上,好像当作实例方法更简洁一些。对array数组计算均值应该是numpy库内的用法,所以运行速度应该相当。
mean和sum这类的函数可以接受一个axis选项参数,用于计算该轴向上的统计值,最终结果是一个少一维的数组:
In [182]: arr.mean(axis=1)
Out[182]: array([ 1.022 , 0.1875, -0.502 , -0.0881, 0.3611])
In [183]: arr.sum(axis=0)
Out[183]: array([ 3.1693, -2.6345, 2.2381, 1.1486])
这里,arr.mean(axis=1)是“计算行的平均值”,arr.sum(axis=0)是“计算每列的和”。
???
axis = 1的时候难道不是计算每一列的值么?axis = 0的时候难道不是计算每一行的值么?写错了?
然而并没有。看到这里的时候我以为我的想法是没有错的,我觉得这比较符合一般人的思维,可是numpy的开发者们有他们自己的想法,经过几次验算后发现事实确实如此。
那怎么帮助理解呢?我想到了一个好办法,而且好像也理解了开发者的想法。比如上例的arr.mean(axis = 1)的结果是一个一维函数,axis = 1代表了它是一列(而python把它显示成了一行确),而mean的值就是从行(其他维度的值)投射到列(这个维度的容器中)然后再在容器中计算相应的统计值。
再推广到三维数组上。比如arr.mean((0,1)),那么0轴与1轴就组成了一个平面,三维数组中的值就沿着2轴向(0,1)平面内无数个容器中投射值,然后再在容器中进行计算获得最终的值。numpy库的开发者还是很厉害的,因为用我一开始的思路,在更高维度很难行得通。
上面的例子是,如果mean里的参数是一个平面的情况,如果mean里的参数是一个轴呢?
其实也是一样的:沿着这根轴的所有面投射到这根轴的容器中,再进行计算就行。
值得注意的地方是,当axis的参数是二维甚至更高维时,应该用元组的形式传入参数。
错误写法:arr.mean(0,1)
正确写法:arr.mean((0,1))
min、max函数与argmin、argmax函数
import numpy as np
arr = np.random.randn(5,2)
arr
array([[-0.5857484 , 0.14827764],
[ 0.3598771 , 0.7664562 ],
[ 0.72843793, -0.10047967],
[ 2.4794738 , -1.69515259],
[ 0.97698715, -0.76028476]])
arr.min(1)
array([-0.5857484 , 0.3598771 , -0.10047967, -1.69515259, -0.76028476])
min与max函数同上,投射的用法与原理也同上,就不做过多阐述。
arr.argmin(1)
array([0, 0, 1, 1, 1], dtype=int64)
argmin与argmax函数将最大值与最小值的索引位置用数组的形式表现出来,如果不传递参数,则只是一个数值不是数组。也是用投射方法去理解比较方便。
cumsum、cumprod函数
前面的方法都是一个静态投射的方法,而cumsum(累加)和cumprod(累乘)函数则是一个动态投射的方法。
静态投射的方法就是我们给定的那个被投射的面或线或更高维度的数组不动,所有其他维度的数值全部投射到该维度之后统一进行计算。
而动态投射的方法就是,我们给出的被投射的面或线或更高维度的数组沿着投射的维度进行运动,然后每运动一次就进行重新投射,再在投射的容器里进行计算(累加就加,累乘就乘)。
In [186]: arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
In [187]: arr
Out[187]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [188]: arr.cumsum(axis=0)
Out[188]:
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]])
In [189]: arr.cumprod(axis=1)
Out[189]:
array([[ 0, 0, 0],
[ 3, 12, 60],
[ 6, 42, 336]])
被投射面沿着投射轴每移动一次,就重新进行一次投射,投射进容器里的数字就重新进行一次计算获得的结果就留在该平面,如此循环,直到到投射轴的终点。
cumsum与cumprod函数与前面的函数多了一个动态的过程,所以获得的结果总是会比前面的多一个维度。
如假设arr是一个三维数组,arr.mean((0,1))就是一个二维数组,而cumsum((0,1))因为有有一个动态过程,且保留了中间结果,所以,它是一个三维数组。
文章代码引用自:《利用Python进行数据分析·第2版》第4章 NumPy基础:数组和矢量计算
作者:SeanCheney
感谢SeanCheney同意引用。