NumPy是什么

NumPy是一个科学计算库

  • 由一个N维数组对象ndarray和多种函数构成

##N维数组对象ndarray

数组和列表的区别

  • 数组是同质的,即数组中的元素类型相同
  • 列表不要求元素类型相同

为什么要有多维数组对象

  • 数组对象可以去掉元素间运算需要的循环,把数组看作一个对象来运算
  • 设置专门的数组对象,经由底层优化,运算速度提高
  • 科学计算中,一个维度的数据基本都是相同类型,使用数组可以预先知道内存布局,从而节省运算和存储空间

ndarray的组成

  • 实际的数据
  • 描述这些数据的元数据(数据维度,数据类型等)
  • 一个数组中的所有元素类型要相同

轴,维度,秩

基本概念

  • 轴即维度
    • 这里轴其实可以理解为坐标轴,三个坐标轴即三维
  • 几何直观理解,一维,二维,三维,分别是线,面,体,一维向量只有一个轴,编号为0,二维矩阵有两个轴,轴0和轴1,轴0为行,轴1为列,三维立体有三个轴,轴012,就是行列高。
  • 数学上,维度是在一定的前提下描述一个数学对象所需的参数个数 ,比如说描述一条线上的元素,只需要一个参数$a(x)$,描述一个面上的元素,则需要$a(x,y)$两个参数 , 描述一个空间里的元素,则需要$a(x,y,z)$三个参数。
  • 具体到我们所说的多维数组对象时,确定最底层的一个基本元素位置需要用到的索引个数即是维度。用二维数组来举一个简单的例子。当我们要获取二维数组的一个元素,我们需要使用 $a[0][0]$, 一共用到了两个坐标索引,所以这个数组的维度是2维。
  • 直观判断维度,即根据括号数量判断 ,看从外到内有几层括号,就有几维
  • 秩:即轴的数量,即有多少维,可以用np.ndim得到

实例讲解(转载)

对于二维数组,0轴表示数组的行,1轴表示数组的列

1
2
3
4
5
arr1 = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> arr1
array([[1,2,3]
       [4,5,6]
       [7,8,9]])

轴示意图如下图

1533000444677

为验证上述结论,对每个轴方向的数字求和

1
2
3
4
>>> arr1.sum(axis=0)
array([12,15,18])
>>> arr1.sum(axis=1)
array([6,15,24])

对于三维数组

1
2
3
4
5
6
7
>>> arr = np.array([[[0, 1, 2, 3], [4, 5, 6, 7]], [[8, 9, 10, 11], [12, 13, 14, 15]]])
>>> arr
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

从外到内有3个括号,则数组arr有3条轴,编号012,直接看出每个轴的方向很困难,可以考虑降维,将三维数组的最内层数组看作一个整体,从而可以将arr变成一个二维数组,获得轴0,轴1

1
2
3
4
5
6
A = [0, 1, 2, 3]
B = [4, 5, 6, 7]
C = [ 8,  9, 10, 11]
D = [12, 13, 14, 15]
arr = [[A, B],
      [C, D]]

1533000916648

此时,对0轴和1轴方向求和,有:(这里的A、B、C、D均为一维数组,对它们进行操作时,要按照向量而非标量的运算法则进行

1
2
3
4
5
6
7
8
9
10
# arr.sum(axis=0) = [A + C, B + D]
# A + C = [0+8, 1+9, 2+10, 3+11] = [8, 10, 12, 14]
# B + D = [4+12, 5+13, 6+14, 7+15] = [16, 18, 20, 22]
>>> arr.sum(axis=0)
array([[ 8, 10, 12, 14],
       [16, 18, 20, 22]])
# arr.sum(axis=1) = [A + B, C + D]
>>> arr.sum(axis=1)
array([[ 4,  6,  8, 10],
       [20, 22, 24, 26]])

那么2轴方向呢?由于A、B、C、D均为一维数组,因此轴2即为最内层数组的行方向

所以对轴2方向进行求和,实际上就是分别将A、B、C、D的元素求和(对一维向量应用sum函数,计算的是该向量所有元素之和)

1533001174826

1
2
3
4
# sum(A) = [0 + 1 + 2 + 3] = [6]
>>> arr.sum(axis=2)
array([[ 6, 22],
       [38, 54]])

由此可知,对于多维数组,numpy对轴的编号是先行后列,由外向内!

实际中三维数组算是维度比较高的了,至于四维及以上的不太常见,因此没必要讲,但是为了验证我们刚才提到的这个结论,我们再举一个四维数组来证明。

我们先生成一个422*2数组,代码如下:

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
>>> arr2 = np.arange(0, 32)
>>> arr2
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])
>>> arr2.reshape(4,2,2,2)
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]]]])

为了手算出结果,同样的,我们需要对原数组进行降维,降维方法是将内部的二维数组分别用字母表示,即有:

1
2
3
4
5
6
7
8
9
10
11
12
A = [[ 0,  1], [ 2,  3]]
B = [[ 4,  5], [ 6,  7]]
C = [[ 8,  9],  [10, 11]]
D = [[12, 13],  [14, 15]]
E = [[16, 17],  [18, 19]]
F = [[20, 21],  [22, 23]]
G = [[24, 25], [26, 27]]
H = [[28, 29], [30, 31]]
arr2 = [[A, B], 
        [C, D],
        [E, F],
        [G, H]]

降维后,对0轴,1轴求和结果为:

$arr.sum(axis=0)=[A+C+E+G , B+D+F+H]$

$arr.sum(axis=1)=[A+B , C+D , E+F , G+H] $

因为A~H均为二维数组,因此其求和受向量运算法则约束,即有:

$A+C+E+G=[A0+C0+E0+G0 , A1+C1+E1+G1]$

$=[[0,1]+[8,9]+[16,17]+[24,25] , [2,3]+[10,11]+[18,19]+[26,27]]$

$=[[0+8+16+24 , 1+9+17+25] , [2+10+18+26 , 3+11+19+27]]$

$=[[48 , 52] , [56 , 60]] $

这与代码运行的结果完全一致

1
2
3
4
5
>>> arr.sum(axis=0)
array([[[48,52],
        [56,60]],
       [[64,68],
        [72,76]]])

四维数组一共有4个轴,至此我们已经把最外层的两个轴(0、1)计算完了,还剩下4-2=2个轴,这两个轴(2,、3)按照我们上面的结论,分别对应内层数组的行(轴0)、列(轴1)。

对轴2、3进行求和计算实际上就是对这些二维数组的行、列分别进行求和。

以A = [[0,1], [2, 3]]来说,对其0、1轴求和分别等于[2, 4]、[1, 5]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> arr2.sum(axis=2)
array([[[ 2,  4],
        [10, 12]],

       [[18, 20],
        [26, 28]],

       [[34, 36],
        [42, 44]],

       [[50, 52],
        [58, 60]]])
>>> arr2.sum(axis=3)
array([[[ 1,  5],
        [ 9, 13]],

       [[17, 21],
        [25, 29]],

       [[33, 37],
        [41, 45]],

       [[49, 53],
        [57, 61]]])

这就证明了我们上面的结论是完全正确的,当维度N≥5N≥5时,原理是一样的,只是稍微繁琐一些。需要注意的是,如果我们要手算,应该进行降维,降维后的维度最好是2,因为这是我们能直观理解的最佳维度,外层计算完后,计算内层时,内层元素进行维度还原时,也最好是二维数组

数组转置

对于数组的转置,当维度N≤2时即表示二维数组的转置,其含义非常明确(行列互换),也很容易理解,但是当维度N≥3时,就不太直观了。

三维数组