python numpy

一、NumPy 简介

  1. NumPyshi 是Python的一个拓展程序库,主要用于科学计算
  2. NumPy支持高端大量的维度数组与矩阵运算
  3. NumPy针对数组运算提供大量的数学函数库

同时,NumPy是SciPy、Matplotlib等扩展路的基础组件

二、基本用法

1、NumPy d的数组

Numpy 的主要数据结构是一个同构多维数组,大于矩阵的概念
维度( dimension)在 Numpy 中称为 axis

NumPy的数组的类被称为 ndarray
NumPy 的 numpy.array 和 Python 标准库中的 array.array 并不相同,NumPy 的 array 仅处理一维数组,因此功能更弱

ndarray包含以下属性(attribute):

  • ndarray.ndim:数组的维度
  • ndarray.shape:数组每个维度的大小,例如一个 n 行 m 列的矩阵的大小为 (n, m)
  • ndarray.size:数组的元素数量,数值上等于数组每个维度大小的乘积
  • ndarray.dtype:数组的数值类型,可以自定义或采用 NumPy 的数值类型,例如
  • numpy.int32、 numpy.int16、 numpy.float64 等
  • ndarray.itemsize:数组的数值类型的大小,例如 float64 的大小是 8( =64/8)
  • ndarray.data:直接读取数组元素,由于没有索引,不推荐使用此属性
>>> import numpy as np
>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> a.shape  
(3, 4)
>>> a.ndim
2
>>> a.dtype.name
'int32'
>>> a.itemsize
4
>>> a.size
12
>>> type(a)
<class 'numpy.ndarray'>

>>> b = np.array([3, 4, 5])
>>> b
array([3, 4, 5])
>>> type(b)
<class 'numpy.ndarray'>
2、创建数组

NumPy提供多种创建数组的方法
例如,NumPy可以直接从标准库的列表或元祖中创建数组

>>> import numpy as np
>>> a = np.array([3, 4, 5])
>>>
>>> a.dtype
dtype('int32')
>>> b = np.array([1.3, 3.3, 5.4])
>>> b.dtype
dtype('float64')

需要注意的是,传递给NumPy 数组的构造函数必须是列表或元祖,不能是多个元素。

>>> a = np.array(1,2,3,4)   # Wrong
>>> a = np.array([1,2,3,4])   # Right
>>> a = np.array((1,2,3,4))  # Right

NumPy数组的构造函数会自动将传入格式转换为NumPy的数组格式
基本库的列表和元组在构造 NumPy 数组时可以混用

>>> b = np.array([(1.2, 2.3), (5, 6)])
>>> b
array([[1.2, 2.3],
       [5. , 6. ]])

同时,构造函数允许指定数据类型

>>> c = np.array([[1, 2], [3, 4]],  dtype=complex)
>>> c
array([[1.+0.j, 2.+0.j],
       [3.+0.j, 4.+0.j]])

在实际应用中,构造数组时具体元素的取值往往不确定,但是数组大小一般会提前确定(比如上次tf神经网络时,先生成特定像素的全0图片【ndarray矩阵】)
因此,NumPy提供了一系列的函数方便构造空数组或特定元素值的数组。

  • 函数 zeros 会创建一个所有元素为 0 的数组
  • 函数 ones 会创建一个所有元素为 1 的数组
  • 函数 empty 会创建一个所有元素为随机数的数组

默认情况下使用上述三个函数创建的数组的数值类型是 float64

>>> np.zeros([3,4])
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
>>> np.ones((2, 3, 4), dtype=np.int16)
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)
>>> np.empty((2,3))
array([[6.17692977e-312, 6.17692977e-312, 6.17692846e-312],
       [6.17692915e-312, 6.17692977e-312, 6.17692915e-312]])

NumPy 提供可迅速生成数列的函数

>>> np.arange(10, 30, 5)
array([10, 15, 20, 25])
>>> np.arange(0, 2, 0.3)
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])

由于小数精度问题,使用 arange 函数较难预测生成数组的元素数量
如果要指定生成的数组长度,可以使用 linspace 函数

>>> from numpy import pi
>>> np.linspace(0, 2, 9)
array([0.  , 0.25, 0.5 , 0.75, 1.  , 1.25, 1.5 , 1.75, 2.  ])
>>> x = np.linspace(0, 2*pi, 100)
>>> f = np.sin(x)
3、打印数组
>>> a = np.arange(6)  # 一维
>>> print(a)
[0 1 2 3 4 5]
>>> b = np.arange(12).reshape(4, 3)  # 二维
>>> print(b)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
>>> c = np.arange(24).reshape(2, 3, 4)  # 三维
>>> print(c)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

如果数组太大, NumPy 会自动将中间的数值替换为省略号,只打印头尾的数值

>>> print(np.arange(100000))
[    0     1     2 ... 99997 99998 99999]

如果需要禁用此行为,可以使用:
np.set_printoptions(threshold=np.nan) 当程序报错时使用

import sys
import numpy as np
np.set_printoptions(threshold=sys.maxsize)
4、基本运算

数组间的数学运算通常为元素级别的运算
运算结果会以新数组的形式返回

>>> a = np.array([10, 20, 30, 40, 50])
>>> b = np.arange(5)
>>> b
array([0, 1, 2, 3, 4])
>>> c = a-b
>>> c
array([10, 19, 28, 37, 46])
>>> b**2
array([ 0,  1,  4,  9, 16], dtype=int32)
>>> 10 * np.sin(a)
array([-5.44021111,  9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a < 35
array([ True,  True,  True, False, False])

乘号(*) 在NumPy的数组运算中是求元素积,而非求数量积(点积)
求数量积需要使用 @ 或 dot() 函数

>>> A = np.array([[1,1], [0,1]])
>>> B = np.array([[2,0],[3,4]])
>>> A * B  # 对应元素相乘
array([[2, 0],
       [0, 4]])
# 点乘
>>> A @ B
array([[5, 4],
       [3, 4]])
>>> A.dot(B)
array([[5, 4],
       [3, 4]])

与标准库类似,某些运算符(例如 += 和 *=)将直接修改左侧变量,而非返回新数组

>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> b += a
>>> b
array([[3.069918  , 3.66590394, 3.7354047 ],
       [3.95409542, 3.42614061, 3.79219622]])
>>> a + b
array([[6.069918  , 6.66590394, 6.7354047 ],
       [6.95409542, 6.42614061, 6.79219622]])

>>> a += b  # b不能自动转换为int类型
Traceback (most recent call last):
  File "", line 1, in <module>
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int32') with casting rule 'same_kind'

如果运算包含多个不同类型的数组,运算结果将向更精确的类型对齐( upcasting)

>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a+b  # c的类型与b保持一致
>>> c
array([1.        , 2.57079633, 4.14159265])
>>> c.dtype.name
'float64'
>>> d = np.exp(c*1j)  # 与复数类型做运算,结果也变成了复数类型
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'

对于大部分一元运算(例如数组求和)来说, ndarray 都直接提供相应的函数

>>> c = np.arange(12).reshape(3,4)
>>> c
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
       
>>> c.sum(axis=0)  # 0维上求和(最外维)
array([12, 15, 18, 21])
>>> c.min(axis=1)  # 取1维上的最小值
array([0, 4, 8])
>>> c.cumsum(axis=1)   # 按行梯形求和
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]], dtype=int32)
5、通用函数

NumPy 提供了一些常用的数学函数,例如 sin、 cos、 exp 等
此类数学函数被称为通用函数( universal functions)
与数学运算类似,通用函数通常是针对数组元素进行操作的

>>> B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([1.        , 2.71828183, 7.3890561 ])
>>> np.sqrt(B)
array([0.        , 1.        , 1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([2., 0., 6.])
6、索引、裁剪、迭代

一维数组可以直接被索引、裁剪、或迭代,行为类似标准库的列表

>>> a = np.arange(10) **3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729], dtype=int32)
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64], dtype=int32)
>>> a[:6:2]
array([ 0,  8, 64], dtype=int32)

>>> a[:6:2] = -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,
         729], dtype=int32)
>>> a[::-1]  # 逆置
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1,
       -1000], dtype=int32)

多维数组每个维度都有一套索引,调用时可用逗号隔开

>>> def f(x, y):
...     return 10*x + y
...
>>> b = np.fromfunction(f, (5,4), dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5, 1]  # 取每行的第二个元素
array([ 1, 11, 21, 31, 41])
>>> b[1:3, :]  # 取前两行
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

如果多维数组的索引没有提供,默认情况下会视为全集

>>> b[-1]  # 等效为 b[-1, :]
array([40, 41, 42, 43])

上述例子中由于其他维度没有提供, NumPy 将视其他纬度为 :,即全集
除了冒号( :)之外, NumPy 也允许使用省略号代表全集,例如: b[i,…]

省略号( …)代表索引中能提供的尽可能多的维度
例如,如果 x 是一个 5 维数组,那么:
x[1,2,…] 等同于 x[1,2,:,:,:]
x[…,3] 等同于 x[:,:,:,:,3]
x[4,…,5,:] 等同于 x[4,:,:,5,:]

>>> c = np.array([[[0,1,2],
...                [10,12,13]],
...              [[100,101,102],
...                [110,112,113]]])
>>> c.shape
(2, 2, 3)

>>> c[1,...]  # c[1,:,:]
array([[100, 101, 102],
       [110, 112, 113]])
       
>>> c[...,2]  # c[:,:,2]
array([[  2,  13],
       [102, 113]])

遍历一个多维数组在默认情况下会遍历第一维度
如果想遍历一个数组的全部元素,可以使用 flat 属性

>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
       
 # 默认只遍历第一个维度      
>>> for row in b:
...     print(row)
...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

# 取全部元素
>>> for element in b.flat:
...     print(element)
...
0
1
2
3
...

三、数组形式变换

1、维度控制

一个数组的形状( shape)即每一维度的元素数量

>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[4., 3., 0., 7.],
       [6., 8., 4., 8.],
       [3., 4., 8., 8.]])
>>> a.shape
(3, 4)

数组的形状可以通过多种方式修改

>>> a.ravel()  # 返回一个压平后的一维数组
array([4., 3., 0., 7., 6., 8., 4., 8., 3., 4., 8., 8.])

>>> a.reshape(6,2)
array([[4., 3.],
       [0., 7.],
       [6., 8.],
       [4., 8.],
       [3., 4.],
       [8., 8.]])
       
>>> a.T  # 转置
array([[4., 6., 3.],
       [3., 8., 4.],
       [0., 4., 8.],
       [7., 8., 8.]])
>>> a.T.shape
(4, 3)

在 ravel() 函数中,输出的一维数组通常是深度优先遍历的( C-style)
因此,如果使用 reshape() 函数,遍历方式也是深度优先
如果希望使用广度优先( FORTRAN-style)或其他遍历方式,可以使用 order 参数

承上所述,使用 reshape() 函数调整维度时,会返回一个新的数组
使用 nadrray.resize() 则会修改本身的纬度

>>> a
array([[4., 3., 0., 7.],
       [6., 8., 4., 8.],
       [3., 4., 8., 8.]])
>>> a.resize((2, 6))
>>> a
array([[4., 3., 0., 7., 6., 8.],
       [4., 8., 3., 4., 8., 8.]])

调整数组维度时,也可以使用 -1 来自动计算剩余维度

>>> a.reshape(3,-1)
array([[4., 3., 0., 7.],
       [6., 8., 4., 8.],
       [3., 4., 8., 8.]])
2、数组叠加和拆分

NumPy 提供了数组叠加的函数 hstack 和 vstack

>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[4., 7.],
       [2., 0.]])
>>> b  = np.floor(10*np.random.random((2,2)))
>>> b
array([[2., 1.],
       [8., 2.]])
# 垂直叠加(0维扩展、添加行)       
>>> np.vstack((a,b))
array([[4., 7.],
       [2., 0.],
       [2., 1.],
       [8., 2.]])
# 水平相加(1维延伸、添加列)   
>>> np.hstack((a,b))
array([[4., 7., 2., 1.],
       [2., 0., 8., 2.]])

类似的, NumPy 提供 hsplit 和 vsplit 两个函数用于拆分数组

>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[3., 3., 9., 7., 4., 3., 2., 5., 8., 6., 0., 3.],
       [6., 0., 5., 9., 7., 9., 3., 5., 1., 0., 2., 3.]])
       
>>> np.hsplit(a,3)   # 指定以第4列为垂直线来分隔
[array([[3., 3., 9., 7.],
       [6., 0., 5., 9.]]), array([[4., 3., 2., 5.],
       [7., 9., 3., 5.]]), array([[8., 6., 0., 3.],
       [1., 0., 2., 3.]])]
       
>>> np.hsplit(a,(3,4))  # # 指定以第4、5列为垂直线来分隔
[array([[3., 3., 9.],
       [6., 0., 5.]]), array([[7.],
       [9.]]), array([[4., 3., 2., 5., 8., 6., 0., 3.],
       [7., 9., 3., 5., 1., 0., 2., 3.]])]

vstack 和 vsplit 是对第一维操作( vertically,对于矩阵来说,即“行”)
hstack 和 hsplit 是对第二维操作( horizontally,对于矩阵来说,即“列”)
如要针对任意维操作:
叠加: concatenate
https://www.numpy.org/devdocs/reference/generated/numpy.concatenate.htm
拆分: array_split
https://www.numpy.org/devdocs/reference/generated/numpy.array_split.html

四、数组复制及内存控制

1、内存控制的概念

NumPy 对于返回过程中的内存控制有以下三种情况:

  • 无复制( No Copy at All):数组完全不会被复制
  • 浅复制( View / Shallow Copy):数组的部分元素会被复
  • 深度复制( Deep Copy):整个数组的内存都会被复制
2、无复制

简单的赋值操作不会复制任何内存

>>> a = np.arange(12)
>>> b = a
>>> b is a
True
>>> b.shape = 3,4
>>> a.shape
(3, 4)

Python 会将可变( mutable)对象作为引用传递,因此也不会复制任何内存

>>> def f(x):
...     x.shape = 4,3
...
>>> f(a)
>>> a.shape
(4, 3)
>>> b.shape
(4, 3)
3、浅复制

view 函数会使用浅复制的方法创建一个数组对象的“视图”

>>> c = a.view()
>>> c is a
False
>>> c.base is a
True
>>> c.flags.owndata
False
>>> c.shape = 2,6  # a的shape没有被改变
>>> a.shape
(4, 3)
>>> c[0,4]=1234  # a的data没有被改变
>>> a
array([[   0,    1,    2],
       [   3, 1234,    5],
       [   6,    7,    8],
       [   9,   10,   11]])

对数组进行裁剪即会使用 view 函数返回原数组的部分属性(即元素)

>>> s = a[:,1:3]
>>> s[:] = 10
>>> a
array([[ 0, 10, 10],
       [ 3, 10, 10],
       [ 6, 10, 10],
       [ 9, 10, 10]])
3、深度复制

copy 函数会返回一个数组的深度复制,包括所有的属性

>>> d = a.copy()
>>> d is a
False
>>> d.base is a  # d不与a共享任何数据
False
>>> d[0,0] = 999
>>> a
array([[ 0, 10, 10],
       [ 3, 10, 10],
       [ 6, 10, 10],
       [ 9, 10, 10]])

从垃圾处理的角度来说,如果从一个巨大的数组中截取了部分元素,而原数组不再被需
要,那么最好使用 copy 函数深度复制截取的子数组,并将原数组销毁

>>> a = np.arange(int(1e8))
>>> b = a[:100].copy()
>>> del a

上面的例子中,如果使用 b = a[:100] 而不使用 copy 函数,那么 a 所占据的内存将不
能被销毁

五、索引技巧

1、数组索引

Numpy相对于Python标准库来说提供了更多的索引工具
例如,NumPy允许通过一组索引来一次性索引一个数组

>>> a = np.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> a = np.arange(12)**2
>>> a
array([  0,   1,   4,   9,  16,  25,  36,  49,  64,  81, 100, 121],
      dtype=int32)
      
>>> i = np.array([1,1,3,8,5])
>>> a[i]
array([ 1,  1,  9, 64, 25], dtype=int32)

>>> j = np.array([[3,4],[9,7]])
>>> a[j] # 形状和j一样
array([[ 9, 16],
       [81, 49]], dtype=int32)

当被检索的数组是多维数组时,传递数组索引将被视为检索第一维度。例如,我们可以
通过检索调色盘来生成一张图片

>>> palette = np.array([[0,0,0],			# black
...                     [255,0,0],			# red
...                     [0,255,0],			# green
...                     [0,0,255],			# blue
...                     [255,255,255]])		#white

>>> image = np.array([[0,1,2,0],  # 每个值对应调色盘里的颜色
...                   [0,3,4,0]])

>>> palette[image]   # (2,4,3)图片
array([[[  0,   0,   0],
        [255,   0,   0],
        [  0, 255,   0],
        [  0,   0,   0]],

       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])

NumPy也支持传递多维数组作为检索索引,但是每一维的形状必须相同

>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> i = np.array([[0,1],   # a的第一维索引
...               [1,2]])
>>> j = np.array([[2,1],   # a的第二维索引
...               [3,3]])
>>> a[i,j]                # i和j必须是相同形状的
array([[ 2,  5],
       [ 7, 11]])

也可以把 i 和 j 放进一个列表里,再传递给 a

>>> l = [i, j]
>>> a[l]      # 和a[i,j]等价
array([[ 2,  5],
       [ 7, 11]])

但是,不能把 i 和 j 放进一个数组里,否则按照 NumPy 的设定将视为查询第一维度

>>> s = np.array([i,j])
>>> a[s]
Traceback (most recent call last):
  File "", line 1, in <module>
IndexError: index 3 is out of bounds for axis 0 with size 3

>>> a[tuple(s)]      # 和a[i,j]等价
array([[ 2,  5],
       [ 7, 11]])

数组索引经常被用在检索时间相关的数组中

>>> time = np.linspace(20,145,5)    # time scale
>>> data = np.sin(np.arange(20).reshape(5,4))  # 4 time-dependent series
>>> time
array([ 20.  ,  51.25,  82.5 , 113.75, 145.  ])
>>> data
array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
       [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
       [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
       [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
       [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
>>> ind = data.argmax(axis=0)   # index of the maxima for each series
>>> ind
array([2, 0, 3, 1], dtype=int64)
>>> time_max = time[ind]
>>> data_max = data[ind, range(data.shape[1])]     # => data[ind[0],0], data[ind[1],1]...
>>> time_max
array([ 82.5 ,  20.  , 113.75,  51.25])
>>> data_max
array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ])
>>> np.all(data_max == data.max(axis=0))
True
2、布尔索引

使用数组索引时,我们提供了一个索引的序列来决定哪些元素应当被选中
使用布尔索引时,我们通过提供布尔值来决定那些元素应当被选中
最简单的布尔索引即为对每一个数组元素都指定一个布尔值

>>> a = np.arange(12).reshape(3,4)
>>> b = a > 4
>>> b     			# b是一个有着a的形状的布尔数组
array([[False, False, False, False],
       [False,  True,  True,  True],
       [ True,  True,  True,  True]])
>>> a[b]
array([ 5,  6,  7,  8,  9, 10, 11])   # 选定元素的一维数组
>>> a[b] = 0         			    # a中大于4的元素赋值为0
>>> a  
array([[0, 1, 2, 3],   
       [4, 0, 0, 0],
       [0, 0, 0, 0]])

与数组索引类似,布尔索引也可以传递多个给多维数组,从而获取对应元素

>>> a = np.arange(12).reshape(3,4)
>>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> b1 = np.array([False,True,True])    		# 第一维
>>> b2 = np.array([True,False,True,False])      # 第二维
>>> a[b1,:]                    # 挑选行
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> a[b1]                     # the same as a[b1,:]
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
       
>>> a[:,b2]                   # 挑选列
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])
>>> a[b1,b2]    #  a weird thing to do?
array([ 4, 10])

NumPy 提供一个 ix_ 函数,能把两个一维数组
转换为一个用于选取方形区域的索引器

>>> arr2 = np.arange(32).reshape((8,4))
>>> 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[np.ix_([1,5,7,2],[0,3,1,2])]
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])

❖ 在这个例子中, ix_ 函数将数组 [1,5,7,2] 和数
组 [0,3,1,2] 产生笛卡尔积,即: (1,0), (1,3),
(1,1), (1,2); (5,0), (5,3), (5,1), (5,2);
(7,0), (7,3), (7,1), (7,2); (2,0), (2,3),
(2,1), (2,2)
❖ 按照坐标 (1,0), (1,3), (1,1), (1,2) 取得
arr2 所对应的元素 4, 7, 5, 6
❖ 按照坐标 (5,0), (5,3), (5,1), (5,2) 取得
arr2 所对应的元素 20, 23, 21, 22
❖ 如此类推

六、进阶功能

❖ 更多的进阶功能可以参考官方教程:
❖ https://www.numpy.org/devdocs/user/quickstart.html
❖ NumPy 的实用小技巧:
❖ https://www.numpy.org/devdocs/user/quickstart.html#tricks-and-tips
❖ 函数详细说明文档及手册:
❖ https://www.numpy.org/devdocs/reference/routines.html
❖ Wes McKinney《利用 Python 进行数据分析》 :
❖ http://product.dangdang.com/25312917.html

你可能感兴趣的:(python,爬虫与数据分析,python,numpy,numpy,numpy总结)