彻底剖析numpy的数值运算

版权声明:本文为博主原创文章,未经博主允许不得转载。 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])

猜你喜欢

转载自blog.csdn.net/gg_18826075157/article/details/78608394