NumPy快速开始(1)

论坛 期权论坛 脚本     
匿名技术用户   2020-12-29 07:37   60   0

最近在学习pytorch的时候,用到许多numpy的函数,学习torch时有些头疼,故重新来学习一下numpy。

这篇文章主要是翻译numpy官方文档1.15版本的快速开始,如果想看英文版的可以点击此链接https://docs.scipy.org/doc/numpy-1.15.1/user/

基本介绍

NumPy的主要对象是同构多维数组。 它是一个元素表(通常是数字),都是相同的类型,由正整数元组索引。 在NumPy维度中称为轴。

例如,3D空间中的一个点坐标 [1,2,1] 有一个维度。这个维度具有3个元素,所以我们说它的长度是3。在下面的例子中,矩阵具有两个维度。第1个 维度的长度为2,第二个维度的长度为3。

[[1,0,0],
[0,1,2]]

NumPy的数组类型称为ndarray。它也被别名数组所知。 请注意,numpy.array与标准Python库类array.array不同,后者仅处理一维数组并提供较少的功能。 ndarray对象的更重要的属性是:

  • ndarray.ndim

数组的轴数(维度)

  • ndarray.shape

数组的维度。这是一个显示数组每一维的大小的整形元组。对于一个n行和m列的矩阵来说,shape就是(n,m)。因此,shape元组的长度就是轴ndim的数目。

  • ndarray.size

数组元素的总数。这等于shape的元素的乘积。

  • ndarray.dtype

一个描述数组中元素类型的对象。可以使用标准的Python类型创建或指定dtype。另外NumPy提供它自己的类型。例如numpy.int32、numpy.int16和numpy.float64

  • ndarray.itemsize

数组中每一个元素的字节大小。例如,元素为 float64 类型的数组的 itemsize 为8(=64/8),而 complex32 类型的数组的 itemsize 为4(=32/8)。它等于 ndarray.dtype.itemsize

  • ndarray.data

这个缓冲区包含数组的真实元素。正常地,我们不需要使用这个属性,因为我们可以通过索引来获得数组中的元素。

一个例子

>>> import numpy as np
>>> a = np.arange(15).reshape(3,5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a.shape
(3, 5)
>>> a.ndim
2
>>> a.dtype.name
'int32'
>>> a.itemsize
4
>>> a.size
15
>>> type(a)
<class 'numpy.ndarray'>
>>> b = np.array([6,7,8])
>>> b
array([6, 7, 8])
>>> type(b)
<class 'numpy.ndarray'>

注:在官方给的例子中,a.dtype.name 的结果是‘int64’,但是在我的机器上是‘int32’。

创建数组

有几种方法来创建数组。例如,可以从常规列表和元组中使用array来创建数组。得到的数组的类型是从Python列表中元素的类型推导出来的。

>>> import numpy as np
>>> a=np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int32')
>>> b = np.array([1.2,3.5,5.1])
>>> b.dtype
dtype('float64')

一个常见的错误在于使用多个数值参数调用 array 函数,而不是提供一个数字列表(List)作为参数。

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

array 将序列的序列转化为两个维度的数组,序列的序列的序列为三维的数组,等等。

>>> b = np.array([(1.5,2,3),(4,5,6)])
>>> b
array([[1.5, 2. , 3. ],
       [4. , 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]])

通常,数组的元素经常时未知的,但是大小是可知的。因此,NumPy提供几个函数来创建具有初始化占位符内容的数组。这可以最小化数组增长的必要,数组增长是一个很耗内存的操作。

函数 zeros 创建一个全为 0 的矩阵,函数 ones 创建一个全为 1 的矩阵,函数 empty 创建一个初始化内容取决于内存的随机数组。默认情况下,创建的数组的 dtype 是 float64 .

>>> np.zeros((3,4))
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
>>> np.array((2,3,4),dtype=np.int16)
array([2, 3, 4], dtype=int16)
>>> 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([[1.5, 2. , 3. ],
       [4. , 5. , 6. ]])

为了创建数字序列,NumPy 提供了类似于 range 的函数,但是返回值是数组而不是列表。

>>> 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)                     #从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)

另见:

array, zeros, zeros_like, ones, ones_like, empty, empty_like, 
arange, linspace, numpy.random.rand, numpy.random.randn, fromfunction, fromfile

打印数组

当你打印数组时,NumPy以与嵌套列表类似的方式显示它,但是具有以下布局:

  • 最后一个轴从左到右打印,

  • 倒数第二个从上到下打印,

  • 其余的也从上到下打印,每个切片与下一个用空行分开。

一维数组被打印为行、二维为矩阵和三维为矩阵列表。

>>> 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]]]

下面会有更多关于 reshape 的介绍。

如果一个数组太大不能打印,NumPy 自动跳过数组的中间部分,只打印边角元素。

>>> print(np.arange(10000))
[   0    1    2 ... 9997 9998 9999]
>>> print(np.arange(10000).reshape(100,100))
[[   0    1    2 ...   97   98   99]
 [ 100  101  102 ...  197  198  199]
 [ 200  201  202 ...  297  298  299]
 ...
 [9700 9701 9702 ... 9797 9798 9799]
 [9800 9801 9802 ... 9897 9898 9899]
 [9900 9901 9902 ... 9997 9998 9999]]

为了取消该默认操作以及强迫 Numpy 打印完整的数组,可以使用 set_printoptions 来改变打印选项。

>>> np.set_printoptions(threshold=np.nan)

基本操作

数组上的算术运算符使用元素级别。一个新的数组被创建并填充结果。

>>> a=np.array([20,30,40,50])
>>> b=np.arange(4)
>>> b
array([0, 1, 2, 3])
>>> c=a-b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9], dtype=int32)
>>> 10*np.sin(a)
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a<35
array([ True,  True, False, False])

与许多矩阵语言不同,乘积操作符 * 在Numpy数组中是元素级操作。矩阵积可以使用 @ 操作符(在python>=3.5)或者 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.97921787, 3.94038392, 3.06511991],
       [3.68390063, 3.73366746, 3.4631797 ]])
>>> a+=b                                 # b 不会自动转换类型为整形
Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    a+=b
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int32') with casting rule 'same_kind'

当操作数组在不同的类型上时,结果数组的类型对应于更一般或更精确的数组(称为向上转换的行为)。

>>> a=np.ones(3,dtype=np.int32)
>>> b=np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c=a+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 的方法一致。

>>> a=np.random.random((2,3))
>>> a
array([[0.78549645, 0.19849634, 0.2812325 ],
       [0.89892312, 0.90676599, 0.61338147]])
>>> a.sum()
3.6842958618593915
>>> a.min()
0.19849634050040577
>>> a.max()
0.9067659870671333

默认情况下,这些操作适用于数组,就好像它是数字列表一样,无论其形状如何。但是,通过指定 axis 参数,你可以沿着数组的指定轴应用操作:

>>> b=np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> b.sum(axis=0)                            #计算每一列的和
array([12, 15, 18, 21])
>>> b.min(axis=1)                            #计算每一行的最小值
array([0, 4, 8])
>>> b.cumsum(axis=1)                         #对于每一行计算累加和
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]], dtype=int32)

通用函数

Numpy 提供了相似的数学函数如 sin, cos, 和 exp. 在 Numpy 中,这些称为通用函数( ufunc )。在NumPy中,这些函数在数组上按元素级别操作,产生一个数组作为输出。

>>> 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])

另见:

all, any, apply_along_axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sort, std, sum, trace, transpose, var, vdot, vectorize, where

索引,切片和迭代

一维数组可以被索引,切片和迭代,就像列表和Python其他序列一样。

>>> a=np.arange(10)*3
>>> a
array([ 0,  3,  6,  9, 12, 15, 18, 21, 24, 27])
>>> a[2]
6
>>> a[2:5]
array([ 6,  9, 12])
>>> a[:6:2]=-1000                #等价于 a[0:6:2]=-1000,从0到6(不包括),间隔为2
>>> a
array([-1000,     3, -1000,     9, -1000,    15,    18,    21,    24,
          27])
>>> a[::-1]                       #对 a 反转
array([   27,    24,    21,    18,    15, -1000,     9, -1000,     3,
       -1000])
>>> for i in a:
 print(i**(1/3))

nan
1.4422495703074083
nan
2.080083823051904
nan
2.46621207433047
2.6207413942088964
2.7589241763811203
2.8844991406148166
3.0

多维数组对于每一个轴都具有索引。这些索引用逗号分隔的元组给出:

>>> 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]
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])

b[i] 方括号中的表达式 i 被视为后面紧跟着 : 的多个实例,用于表示剩余轴。NumPy也允许你使用三个点写为 b[i,...]

三个点( ... )表示产生完整索引元组所需的冒号。例如,如果 x 是轴为的5数组(即,它具有5个轴),则

  • x[1,2, . . .] 等价于 x[1, 2, :, :, :]
  • x[. . . .,3] 等价于 x[ :, :, :, :,3] ,
  • x[4,. . .,5,:] 等价于 x[4, :,:, 5, :]
>>> c = np.array( [[[  0,  1,  2],               # 3D数组(两个2D数组连接)
...                 [ 10, 12, 13]],
...                [[100,101,102],
...                 [110,112,113]]])
>>> c.shape
(2, 2, 3)
>>> c[1,...]                                   # 等价于 c[1,:,:] 或者 c[1]
array([[100, 101, 102],
       [110, 112, 113]])
>>> c[...,2]                                   # 等价于 c[:,:,2]
array([[  2,  13],
       [102, 113]])

迭代 多维数组时相对于第一个轴完成的:

>>> 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]

但是,如果想要对数组中的每个元素执行操作,可以使用 flat 属性,该属性是数组中所有元素的迭代器:

>>> for element in b.flat:
 print(element)

 
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

另见:

Indexing, Indexing (reference), newaxis, ndenumerate, indices

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP