【Python 模块学习】Numpy之转置和cumsum 详细理解

1, Ndarray 的转置

转置有三种方式,transpose方法、T属性以及swapaxes方法。

1, .T,适用于一、二维数组

In [1]: import numpy as np

In [2]: arr = np.arange(20).reshape(4,5)#生成一个4行5列的数组

In [3]: arr
Out[3]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [4]: arr.T #求转置
Out[4]:
array([[ 0,  5, 10, 15],
       [ 1,  6, 11, 16],
       [ 2,  7, 12, 17],
       [ 3,  8, 13, 18],
       [ 4,  9, 14, 19]])

2. 对于高维数组,transpose需要用到一个由轴编号组成的元组,才能进行转置。

对多维数组来说,确定最底层的一个基本元素位置需要用到的索引个数即是维度。这句话的理解可以结合我索引和切片的那篇文章理解。

首先先定义一个简单的三维数组,可以知道shape为(2,3,4),对应0,1,2编号(可以理解为shape返回元祖(2,3,4)的索引)。

In [1]: import numpy as np

In [2]: arr=np.arange(24).reshape(2,3,4)

In [3]: arr
Out[3]:
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]]])

In [4]: arr.shape
Out[4]: (2, 3, 4)  #说明这是一个2*3*4的数组(矩阵),返回的是一个元组,可以对元组进行索引,也就是0,1,2

3.引入三维坐标便于理解

坐标中的(0,1,2)(蓝色标的)三个维度就是shape返回元祖的索引编号,至于为什么垂直于底面的轴编号是0,可以联系二维数组进行推理。

如上图,将arr数组想象成三维空间,如长方体,0-11 12位数在长方体的顶面,12-23在长方体的底面。

  • 当axis=0时,剩余的1,2维度组成了垂直于轴0的平面,这个平面上的数组有
[0,1,2,3
 4,5,6,7
8,9,10,11]     #数组0-1

[12,13,14,15
16,17,18,19
20,21,22,23]   #数组0-2
  • 当axis=1时,剩余的0,2维度组成了垂直于轴1的平面,这个平面上的数组有
[0,1, 2, 3
12,13,14,15]      #数组1-1
[4,5,6,7
16,17,18,19]      #数组1-2
[8,9,10,11
20,21,22,23]      #数组1-3
  • 当axis=2时,剩余的0,1维度组成了垂直于轴2的平面,这个平面上的数组有
[0, 4,8
12,16,20]    #数组2-1
[1,5,9
13,17,21]    #数组2-2
[2, 6,10
14,18,22]    #数组2-3
[3,7,11
15,19,23]    #数组2-4
形状 索引
2 0
3 1
4 2

transpose参数的真正意义在于这个shape元组的索引。多维元组它本身是如下的N维数组:

In [8]: arr.transpose(0,1,2)
Out[8]:
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]]])

那么它的转置就应该是arr.transpose(0,2,1)如下,(0->2,2->4,1->3 说明转置后是一个2个,4行,3 列的多维数组

In [9]: arr.transpose(0,2,1)
Out[9]:
array([[[ 0,  4,  8],
        [ 1,  5,  9],
        [ 2,  6, 10],
        [ 3,  7, 11]],

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

 他们是怎么计算得来的呢?

transpose之前3的索引是(0,0,3),8的索引是(0,2,0)。
现在transpose将原来3的索引顺序(0,0,3)改为了(0,3,0),8的索引为(0,0,2)

shape[0],shape[1],shape[2]原来分别表示矩阵3个维度的索引,tranpose之后根据transpoe的位置参数,索引的对应关系也发生变化,transpose(0,2,1)就表示原来的shape[1]和shape[2]对调,shape[0]不变,比如你举的例子里面原来8的索引为(0,2,0),transpose之后1和2对调,变成了(0,0,2),其他元素的位置也类似改变。

这也说明了,transpose依赖于shape

4.根据以上三个维度,以下sum()函数实例就很好理解了。

A.轴编号为0时,数组0-1和数组0-2平面叠加

In [5]: np.sum(arr,axis=0)
Out[5]:
array([[12, 14, 16, 18],
       [20, 22, 24, 26],
       [28, 30, 32, 34]])

B.轴编号为1时,数组1-1和数组1-2和数组1-3平面叠加

In [6]: np.sum(arr,axis=1)
Out[6]:
array([[12, 15, 18, 21],
       [48, 51, 54, 57]])

C.轴编号为2时,数组2-1和数组2-2、2-3、2-4平面叠加

In [7]: np.sum(arr,axis=2)
Out[7]:
array([[ 6, 22, 38],
       [54, 70, 86]])

5.transpose()中三个轴编号的位置变化理解

transpose(a,b,c)其中a轴编号即为参考编号,垂直于a的平面即为所有平面,该平面上的数据再根据b,c相对于(0,1,2)的位置关系进行改变,下面以实例举例说明

A.transpose(0,1,2)对应的就是arr数组原形

In [8]: arr.transpose(0,1,2)
Out[8]:
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]]])

B.transpose(0,2,1),即以0为参考编号,数组0-1和0-2即为所求平面数组,但是2,1相对于(0,1,2)后面的轴编号进行了交换,所以数组0-1/0-2要以对角线进行.T转置(与二维数组的转置一样),所以结果如下。其余同理。

In [9]: arr.transpose(0,2,1)
Out[9]:
array([[[ 0,  4,  8],
        [ 1,  5,  9],
        [ 2,  6, 10],
        [ 3,  7, 11]],

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

C.以transpose(2,1,0)来验证以上操作。2为参考编号,数组2-1/2-2/2-3/2-4即为所求平面,其中(2,1,0)中1,0位置相较于(0,1,2)进行了互换,所以转置,结果如下。

In [10]: arr.transpose(2,1,0)
Out[10]:
array([[[ 0, 12],
        [ 4, 16],
        [ 8, 20]],

       [[ 1, 13],
        [ 5, 17],
        [ 9, 21]],

       [[ 2, 14],
        [ 6, 18],
        [10, 22]],

       [[ 3, 15],
        [ 7, 19],
        [11, 23]]])

6.swapaxes(a,b)函数中两个轴编号理解

首先从词义上得知swap是“交换”的意思,swapaxes(a,b)函数则应该是a,b两个轴编号进行位置互换后数组的变化,这样原理和以上transpose相同了,下面实例验证

arr.swapaxes(0,1)=arr.swapaxes(1,0)=arr.transpose(1,0,2)

In [13]: arr.swapaxes(1,0)
Out[13]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
-------------------------------------------
In [14]: arr.swapaxes(0,1)
Out[14]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
------------------------------------------------
In [15]: arr.transpose(1,0,2)
Out[15]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])

另外举一个简单点的例子来理解swapaxes

In [67]: arr2 = np.arange(16).reshape(2,2,4)           
                                                       
In [68]: arr2                                          
Out[68]:                                               
array([[[ 0,  1,  2,  3],                              
        [ 4,  5,  6,  7]],                             
                                                       
       [[ 8,  9, 10, 11],                              
        [12, 13, 14, 15]]])                            
                                                       
In [69]: arr2.shape                                    
Out[69]: (2, 2, 4)                                     
                                                       
In [70]: arr2.swapaxes(1,2)                            
Out[70]:                                               
array([[[ 0,  4],                                      
        [ 1,  5],                                      
        [ 2,  6],                                      
        [ 3,  7]],                                     
                                                       
       [[ 8, 12],                                      
        [ 9, 13],                                      
        [10, 14],                                      
        [11, 15]]])   

In [4]: arr2.swapaxes(1,0)#转置,对比transpose(1,0,2)
Out[4]:
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])                                 
In [59]: arr1 = np.arange(12).reshape(2,2,3) 
In [60]: arr1 
Out[60]: 
array([[[ 0, 1, 2], 
        [ 3, 4, 5]], 
       [[ 6, 7, 8], 
        [ 9, 10, 11]]])

2, cumsum 的计算过程详解

cumsum函数定义:

cumsum(a, axis=None, dtype=None, out=None)  
a.cumsum(axis=None, dtype=None, out=None)
  返回:沿着指定轴的元素累加和所组成的数组,其形状应与输入数组a一致

其中cumsum函数的参数:

a:数组
axis:轴索引,整型,若a为n维数组,则axis的取值范围为[0,n-1]
dtype:返回结果的数据类型,若不指定,则默认与a一致。
out:数据类型为数组。用来放置结果的替代输出数组,它必须具有与输出结果具有相同的形状和缓冲长度

1.对于一维数组而言:

import numpy as np
arr=np.array([1,2,3,4,5,6,7,8,9])
result=arr.cumsum()    #此时axis只能取0,因此,axis=0可不写
#result: array([ 1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)
输出结果的数组result[i]的结果为sum(arr[:i+1])。

2.对于二维数组而言

import numpy as np
arr=np.array([[1,2,3],[4,5,6],[7,8,9]])
#沿着axis=0轴计算
result1=arr.cumsum(0)   #array([[ 1,  2,  3],[ 5,  7,  9],[12, 15, 18]], dtype=int32)
#沿着axis=1轴计算
result2=arr.cumsum(1)   #array([[ 1,  3,  6],[ 4,  9, 15],[ 7, 15, 24]], dtype=int32)
#arr.cumsum()并不是arr.cumsum(0)和arr.cumsum(1)的并集,而是将arr重塑为一维数组后的,再计算cumsum()的结果
arr.cumsum()#array([ 1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)

Cumsum :计算轴向元素累加和,返回由中间结果组成的数组
重点就是返回值是“由中间结果组成的数组
以下代码在python3.7版本运行成功!
下面看代码,定义一个2*2*3的数组,所以其shape是2,2,3,索引分别0,1,2

形状 索引
2 0
2 1
3 2




 

3.对于n维数组而言,以3 维举例:

arr=np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
result1=arr.cumsum(0)    #array([[[ 1,  2],[ 3,  4]],[[ 6,  8],[10, 12]]], dtype=int32)
result2=arr.cumsum(1)    #array([[[ 1,  2],[ 4,  6]],[[ 5,  6],[12, 14]]], dtype=int32)
result3=arr.cumsum(2)    #array([[[ 1,  3],[ 3,  7]],[[ 5, 11],[ 7, 15]]], dtype=int32)
输出结果的数组result1[i][j][k]的结果为sum(arr[:i+1,j,k]);

输出结果的数组result2[i][j][k]的结果为sum(arr[i,:j+1,k]);

输出结果的数组result3[i][j][k]的结果为sum(arr[i,j,:k+1])。

n维数组(n>3)的以此类推。

3, tile函数定义:

tile(A, reps) 
返回一个数组,该数组是通过复制A reps次获得。

tile参数说明:

A:输入数组
reps:一个元组,代表沿各个轴重复A的次数。ps:A的顺序并不是单纯的按照axis增大或减小的顺序。
代码示例:

#输入一维数组  
a = np.array([0, 1, 2])
#沿axis=1方向上复制2次,默认#沿axis=0方向上复制1次
np.tile(a, 2)          #array([0, 1, 2, 0, 1, 2])
#沿axis=0方向上复制2次,#沿axis=1方向上复制1次
np.tile(a, (2, 1))     # array([[0, 1, 2],[0, 1, 2]])
##沿axis=2方向上复制2次,沿axis=0方向上复制1次,沿axis=1方向上复制3次,
np.tile(a, (2, 1, 3))  #array([[[0, 1, 2, 0, 1, 2, 0, 1, 2]],[[0, 1, 2, 0, 1, 2, 0, 1, 2]]])
#输入二维数组
b = np.array([[1, 2], [3, 4]])
#沿axis=1方向上复制2次,默认#沿axis=0方向上复制1次
np.tile(b, 2)          #array([[1, 2, 1, 2],[3, 4, 3, 4]])
#沿axis=0方向上复制2次,#沿axis=1方向上复制1次
np.tile(b, (2, 1))    #array([[1, 2],[3, 4],[1, 2],[3, 4]])
 

猜你喜欢

转载自blog.csdn.net/Babyfatliang/article/details/87626362