版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gg_18826075157/article/details/78608394
彻底剖析numpy的数值运算
1.矢量与标量的运算
>>> a = np.array([1, 2, 3, 4])
>>> a + 1
array([2, 3, 4, 5])
>>> 2**a
array([ 2, 4, 8, 16])
2.矢量之间进行点运算
>>> b = np.ones(4) + 1
>>> a - b
array([-1., 0., 1., 2.])
>>> a * b
array([ 2., 4., 6., 8.])
>>> j = np.arange(5)
>>> 2**(j + 1) - j
array([ 2, 3, 6, 13, 28])
当然,numpy对于这些操作都做了十分细致的优化。
>>> a = np.arange(10000)
>>> %timeit a + 1
10000 loops, best of 3: 24.3 us per loop
>>> l = range(10000)
>>> %timeit [i+1 for i in l]
1000 loops, best of 3: 861 us per loop
值得注意的是,两个array之间进行*运算,并不是进行矩阵相乘(如果想进行矩阵间相乘,应该调用dot()方法)。
>>> c = np.ones((3, 3))
>>> c * c # NOT matrix multiplication!
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> c.dot(c)
array([[ 3., 3., 3.],
[ 3., 3., 3.],
[ 3., 3., 3.]])
3.比较运算
>>> a = np.array([1, 2, 3, 4])
>>> b = np.array([4, 2, 2, 4])
>>> a == b
array([False, True, False, True], dtype=bool)
>>> a > b
array([False, False, True, False], dtype=bool)
>>> a = np.array([1, 2, 3, 4])
>>> b = np.array([4, 2, 2, 4])
>>> c = np.array([1, 2, 3, 4])
>>> np.array_equal(a, b)
False
>>> np.array_equal(a, c)
True
4.逻辑运算
>>> a = np.array([1, 1, 0, 0], dtype=bool)
>>> b = np.array([1, 0, 1, 0], dtype=bool)
>>> np.logical_or(a, b)
array([ True, True, True, False], dtype=bool)
>>> np.logical_and(a, b)
array([ True, False, False, False], dtype=bool)
5.超越函数
>>> a = np.arange(5)
>>> np.sin(a)
array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ])
>>> np.log(a)
array([ -inf, 0. , 0.69314718, 1.09861229, 1.38629436])
>>> np.exp(a)
array([ 1. , 2.71828183, 7.3890561 , 20.08553692, 54.59815003])
6.转置操作
>>> a = np.triu(np.ones((3, 3)), 1) # see help(np.triu)
>>> a
array([[ 0., 1., 1.],
[ 0., 0., 1.],
[ 0., 0., 0.]])
>>> a.T
array([[ 0., 0., 0.],
[ 1., 0., 0.],
[ 1., 1., 0.]])
请注意!!转置操作返回的是原array的视图,即两者共享内存。
7.求和聚合
>>> x = np.array([1, 2, 3, 4])
>>> np.sum(x)
10
>>> x.sum()
10
或者,分别对每一行/列进行求和聚合:
>>> x = np.array([[1, 1], [2, 2]])
>>> x
array([[1, 1],
[2, 2]])
>>> x.sum(axis=0) # 列聚合
array([3, 3])
>>> [x[:, 0].sum(), x[:, 1].sum()] # ←相当于
[3, 3]
>>> x.sum(axis=1) # 行聚合
array([2, 4])
>>> [x[0, :].sum(), x[1, :].sum()] # ←相当于
[2, 4]
相同地,求和聚合也适用于更高维度的情况:
>>> x = np.array([[[1, 2], [3, 4]],[[5, 6], [7, 8]]])
>>> x.sum(axis=2)
[[ 3 7]
[11 15]]
>>> [[x[0, 0, :].sum(), x[0, 1, :].sum()], [x[1, 0, :].sum(), x[1, 1, :].sum()]] # ←相当于
[[3, 7], [11, 15]]
8.其他聚合操作
其他聚合操作的用法与上面介绍的求和聚合大同小异:
8.1.求极值
>>> x = np.array([1, 3, 2])
>>> x.min()
1
>>> x.max()
3
>>> x.argmin() # 最小值的索引下标
0
>>> x.argmax() # 最大值的索引下标
1
8.2.逻辑聚合
>>> np.all([True, True, False]) # 相当于所有元素进行and的reduce操作
False
>>> np.any([True, True, False]) # 相当于所有元素进行or的reduce操作
True
逻辑聚合常常与比较运算一起使用:
>>> a = np.zeros((100, 100))
>>> np.any(a != 0)
False
>>> np.all(a == a)
True
>>> a = np.array([1, 2, 3, 2])
>>> b = np.array([2, 2, 3, 2])
>>> c = np.array([6, 4, 4, 5])
>>> ((a <= b) & (b <= c)).all()
True
8.3.其他统计值
>>> x = np.array([1, 2, 3, 1])
>>> y = np.array([[1, 2, 3], [5, 6, 1]])
>>> x.mean()
1.75
>>> np.median(x)
1.5
>>> np.median(y, axis=-1) # 最后一维,即进行行聚合
array([ 2., 5.])
>>> x.std() # 求标准差
0.82915619758884995
9.广播机制
对于不同维度大小的array,同样可以进行运算,可以视作是低维度array对于高维度array的“广播”或者“扩散”。
>>> a = np.tile(np.arange(0, 40, 10), (3, 1)).T
>>> a
array([[ 0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
>>> b = np.array([0, 1, 2])
>>> a + b
array([[ 0, 1, 2],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]])
如果还是不理解,可以参考下图,以下的三个矩阵运算在广播机制的作用下其实是一样的:
“广播机制”还存在于赋值运算中,下面的小技巧可谓方便且实用:
>>> a = np.ones((4, 5))
>>> a
array([[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
>>> a[0] = 2
>>> a
array([[ 2., 2., 2., 2., 2.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
10.shape操作
10.1.展开操作(ravel)
将任意shape的array统一展开为一个一维array
>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> a.ravel()
array([1, 2, 3, 4, 5, 6])
>>> a.T
array([[1, 4],
[2, 5],
[3, 6]])
>>> a.T.ravel()
array([1, 4, 2, 5, 3, 6])
10.2.Reshape操作
Reshape操作可以看作是ravel的逆操作
>>> a.shape
(2, 3)
>>> b = a.ravel()
>>> b = b.reshape((2, 3))
>>> b
array([[1, 2, 3],
[4, 5, 6]])
或者直接对原始array进行Reshape操作
>>> a.reshape((2, -1)) # -1代表该数值根据a的元素总数动态计算得出
array([[1, 2, 3],
[4, 5, 6]])
!!!值得注意的是:reshape()函数的返回值有可能是视图,也有可能是全新的拷贝
10.3.维度追加
如果使用np.newaxis对象作为array的索引下标,就可以进行追加维度的操作。
>>> z = np.array([1, 2, 3])
>>> z
array([1, 2, 3])
>>> z[:, np.newaxis] # 相当于z.reshape((3, 1))
array([[1],
[2],
[3]])
>>> z[np.newaxis, :] # 相当于z.reshape((1, 3))
array([[1, 2, 3]])
10.4.维度替换
>>> a = np.arange(4*3*2).reshape(4, 3, 2)
>>> a.shape
(4, 3, 2)
>>> a[0, 2, 1]
5
>>> b = a.transpose(1, 2, 0)
>>> b.shape
(3, 2, 4)
>>> b[2, 1, 0]
5
当然,维度替换的返回值是毋庸置疑的视图。
10.5.Resize操作
它的用法和作用与Reshape操作相类似
>>> a = np.arange(4)
>>> a.resize((8,))
>>> a
array([0, 1, 2, 3, 0, 0, 0, 0])
但是它只能用于只有一个引用变量的array,否则会报错:
>>> b = a
>>> a.resize((4,))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: cannot resize an array that has been referenced or is
referencing another array in this way. Use the resize function
11.排序操作
以某个维度为轴进行排序操作:
>>> a = np.array([[4, 3, 5], [1, 2, 1]])
>>> b = np.sort(a, axis=1)
>>> b
array([[3, 4, 5],
[1, 1, 2]])
也可以获取排序后各元素在原array中的索引下标:
>>> a = np.array([4, 3, 1, 2])
>>> j = np.argsort(a)
>>> j
array([2, 3, 1, 0])
>>> a[j]
array([1, 2, 3, 4])