视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
深入理解NumPy简明教程---数组2
2020-11-27 14:26:30 责编:小采
文档


NumPy数组(2、数组的操作)

基本运算

数组的算术运算是按元素逐个运算。数组运算后将创建包含运算结果的新数组。

>>> 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]) 
>>> 10*np.sin(a) 
array([ 9.12945251,-9.88031624, 7.4511316, -2.62374854]) 
>>> a<35 
array([True, True, False, False], dtype=bool)

与其他矩阵语言不同,NumPy中的乘法运算符*按元素逐个计算,矩阵乘法可以使用dot函数或创建矩阵对象实现(后续章节会介绍)

>>> A= np.array([[1,1], 
...[0,1]]) 
>>> B= np.array([[2,0], 
...[3,4]]) 
>>> A*B # 逐个元素相乘 
array([[2, 0], 
    [0, 4]]) 
>>> np.dot(A,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.69092703, 3.8324276, 3.0114541], 
     [ 3.18679111, 3.3039349, 3.376002]]) 
>>> a+= b # b转换为整数类型 
>>> a 
array([[6, 6, 6], 
 [6, 6, 6]])

当数组中存储的是不同类型的元素时,数组将使用占用更多位(bit)的数据类型作为其本身的数据类型,也就是偏向更精确的数据类型(这种行为叫做upcast)。

>>> a= np.ones(3, dtype=np.int32) 
>>> b= np.linspace(0,np.pi,3) 
>>> b.dtype.name 
'float' 
>>> c= a+b 
>>> c 
array([ 1., 2.57079633, 4.14159265]) 
>>> c.dtype.name 
'float' 
>>> d= exp(c*1j) 
>>> d 
array([ 0.54030231+0.84147098j,-0.84147098+0.54030231j, 
     -0.54030231-0.84147098j]) 
>>> d.dtype.name 
'complex128'

许多非数组运算,如计算数组所有元素之和,都作为ndarray类的方法来实现,使用时需要用ndarray类的实例来调用这些方法。

>>> a= np.random.random((2,3)) 
>>> a 
array([[ 0.65806048, 0.58216761, 0.59986935], 
 [ 0.6004008, 0.41965453, 0.71487337]]) 
>>> a.sum() 
  3.5750261436902333 
>>> a.min() 
 0.419654534104032 
>>> a.max() 
 0.714873370955819

这些运算将数组看作是一维线性列表。但可通过指定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]])

索引,切片和迭代

和列表和其它Python序列一样,一维数组可以进行索引、切片和迭代操作。

>>> a= np.arange(10)**3 #记住,操作符是对数组中逐元素处理的! 
>>> a 
array([0, 1, 8, 27, , 125, 216, 343, 512, 729]) 
>>> a[2] 
8 
>>> a[2:5] 
array([ 8, 27, ]) 
>>> a[:6:2]= -1000 # 等同于a[0:6:2]= -1000,从开始到第6个位置,每隔一个元素将其赋值为-1000 
>>> a 
array([-1000, 1,-1000, 27,-1000, 125, 216, 343, 512, 729]) 
>>> a[: :-1] # 反转a 
array([ 729, 512, 343, 216, 125,-1000, 27,-1000, 1,-1000]) 
>>>for i in a: 
... print i**(1/3.), 
... 
nan 1.0 nan 3.0 nan 5.0 6.0 7.0 8.0 9.0

数组可以每个轴有一个索引。这些索引由一个逗号分割的元组给出。

>>>def f(x,y): 
... return 10*x+y 
... 
>>> b= np.fromfunction(f,(5,4),dtype=int) #fromfunction是一个函数,下篇文章介绍。 
>>> 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,:],-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= array( [ [[ 0, 1, 2], #三维数组(两个2维数组叠加而成) 
    ...[ 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]])

    数组的遍历是以是第一个轴为基础的:

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

    形状(shape)操作

    更改数组的形状

    数组的形状取决于其每个轴上的元素个数:

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

    可以用多种方式修改数组的形状:

    >>> a.ravel() # 平坦化数组 
    array([ 7., 5., 9., 3., 7., 2., 7., 8., 6., 8., 3., 2.]) 
    >>> a.shape= (6, 2) 
    >>> a.transpose() 
    array([[ 7., 9., 7., 7., 6., 3.], 
     [ 5., 3., 2., 8., 8., 2.]])

    由ravel()展平的数组元素的顺序通常是“C风格”的,就是以行为基准,最右边的索引变化得最快,所以元素a[0,0]之后是a[0,1]。如果数组改变成其它形状(reshape),数组仍然是“C风格”的。NumPy通常创建一个以这个顺序保存数据的数组,所以ravel()通常不需要创建起调用数组的副本。但如果数组是通过切片其它数组或有不同寻常的选项时,就可能需要创建其副本。还可以同过一些可选参数函数让reshape()和ravel()构建FORTRAN风格的数组,即最左边的索引变化最快。

    reshape函数改变调用数组的形状并返回该数组,而resize函数改变调用数组自身。

    >>> a 
    array([[ 7., 5.], 
     [ 9., 3.], 
     [ 7., 2.], 
     [ 7., 8.], 
     [ 6., 8.], 
     [ 3., 2.]]) 
    >>> a.resize((2,6)) 
    >>> a 
    array([[ 7., 5., 9., 3., 7., 2.], 
     [ 7., 8., 6., 8., 3., 2.]])

    如果在reshape操作中指定一个维度为-1,那么其准确维度将根据实际情况计算得到

    下载本文
    显示全文
    专题