ufunc是universal function的缩写,意思是这些函数能够作用于narray对象的每一个元素上,而不是针对narray对象操作,numpy提供了大量的ufunc的函数。这些函数在对narray进行运算的速度比使用循环或者列表推导式要快很多,但请注意,在对单个数值进行运算时,python提供的运算要比numpy效率高。
numpy提供的四则ufunc有如下一些:
numpy同时提供了=、<、>等这些比较运算符,这些运算符的结果是bool值或者bool数组。
ufunc函数对象本身还有一些方法函数,这些方法只对两个输入、一个输出的ufunc 函数有效,其他的ufunc对象调用这些方法时会抛出ValueError异常。 (1). reduce(),沿着指定轴对数组进行操作,相当于将相应的操作放到该轴元素之间。
np.add.reduce([1,2,3]) #1+2+3=6 np.add.reduce([[1,2,3],[4,5,6]]) #[1+4,2+5,3+6]=[5,7,9] np.add.reduce([[1,2,3],[4,5,6]],axis=1) #[1+2+3,4+5+6]=[6,15](2). accumulate()和reduce()类似,区别时是前者会保留中间结果:
np.add.accumulate([1,2,3]) #[1,1+2,1+2+3]=[1,3,6] np.add.accumulate([[1,2,3],[4,5,6]],axis=1) # array([[ 1, 3, 6], [ 4, 9, 15]])(3). reduceat()方法计算多纽reduce()的结果,通 过 indices参数指定一系列的起始和终止位置。它的计算有些特别,,计算的方法如下:
if indices[i] < indices[i+1]: result[i] = <op>.reduce(a[indices[i]:indices[i+1]]) else: result[i] = a[indices[i]] #result[-1]的计算如下: <op>.reduce(a[indices[-1]:]) 例: a = np.array([1,2,3,4]) result = np.add.reduceat(a, indices=[0,1,0,2,0,3,0]) ## result array([1,2,3,3,6,4,10]) ## 计算过程如下: 1 : a[0] -> 1 2 : a[1] -> 2 3 : a[0] + a[1] -> 1 + 2 3 : a[2] -> 3 6 : a[0] + a[1] + a[2] -> 1 + 2 + 3 = 6 4 : a[3] -> 4 10 :a[0] + a[1] + a[2] + a[4] - > 1 + 2 + 3 + 4 = 1 0在前一篇文章中我们提到过多维数组,现在我们回头再看看多维数组的下标取数据。首先,多维数组的下标应该是一个长度和数组的维数相同的元组。如栗下标元组的长度比数组的维数大,就会出错;如果小,就 会 在 下 标 元 组 的 后 而 补 ,使得它的长度与数组维数相同。如果下标对象不是元组,则 numpy会首先把它转换为元组。这种转换可能会和用户所希望的不一致,因此为了避免出现问题,请 “显式”地使用元组作为下标。
a = np.arange(3*4*5).reshape(3,4,5) array([[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]], [[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]], [[40, 41, 42, 43, 44], [45, 46, 47, 48, 49], [50, 51, 52, 53, 54], [55, 56, 57, 58, 59]]]) lidx=[[0],[1]] #a[lidx] aidx = np.array(lidx) #a[aidx] array([[[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]], [[[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]]]])可以看到,numpy把列表[[0],[1]]转换成元组([0],[1]),而把数组对象转换成(aidx,:😅。 如果利用数组作为下标,但数组的维度都不一样,那么这个时候这些数组将会应用广播规则把这些数组转换成一样,转换的规则是上面说到的先用1补足然后取各个维度的最大值。
i0 = np.array([[1,2,1],[0,1,0]]) i1 = np.array([[[0]],[[1]]]) i2 = np.array([[[2,3,2]]]) #print i0.shape (2, 3) #print i1.shape (2, 1, 1) #print i2.shape (1, 1, 3) # i0补齐之后为 (1,2,3),然后取最大值为 (2,2,3)这里将所有的数组进行广播,把所有的数组转换成shape=(2,2,3),利用numpy.broadcast_arrays()可以查看广播后的数组:
id0,id1,id2=np.broadcast_arrays(i0,i1,i2) #id0 [[[1 2 1] [0 1 0]] [[1 2 1] [0 1 0]] #id1 [[[0 0 0] [0 0 0]] [[1 1 1] [1 1 1]]] #id2 [[[2 3 2] [2 3 2]] [[2 3 2] [2 3 2]]]然后利用下标取元素时,例如i,j,k=1,1,1时,取得的元素应该是a[id0[i,j,k],id1[i,j,k],id2[i,j,k]]=a[1,1,3]=28。下标中含有切片时,首先来看第一种,就是整数数组时连续的,也就是数组之间没有切片,例如a[1:3,i0,i1],这种情况下,首先会把整数数组(i0,i1)广播,然后将切片的长度放到相应的位置构成一个维度,i0,i1广播后的shape=(2,2,3),切片的长度为2,所以最后的shape=(2,2,2,3)。最后的结果是a[1:3,id0[i,j,k],id1[i,j,k]]。再者,如果切片是再整数数组之间,那么同样会将数组广播,然后把切片位置替换为数组的维度或者切片的长度添加到索引的最后面,如a[i0,:,i1],i0,i1广播后的shape=(2,2,3),数组a的第二个轴的长度为4,所以最后的shape=(2,2,3,4)。 用bool数组作为下标时,会将bool数组中为True的索引组成一个整数数组,然后以此数组作为下标。相当于用numpy.nonzero(bool_array)的结果,例如:
b2 = np.array([[True,False,True],[True,False,False]]) np.nonzero(b2) ## (array([0, 0, 1]), array([0, 2, 0])) ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## 相当于取[0,0],[0,2],[1,0]python科学计算之numpy——ufunc函数