Deeplearning 笔记:数组转置 empty_like tile 广播等

2. Numpy

2.13 数组转置

数组转置就是对数组的维度相互调整。可以用到三个方法:transpose函数,T属性,和swapaxes函数

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
>>> a = np.arange(24)
>>> a
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])
>>> np.transpose(a) #对于一位数组,转置之后不变
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 = a.reshape(3, 8)
>>> b
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]])
>>> c = np.transpose(b) #二维数组,数组形状倒置,从(3, 8)到(8, 3)
>>> c
array([[ 0, 8, 16],
[ 1, 9, 17],
[ 2, 10, 18],
[ 3, 11, 19],
[ 4, 12, 20],
[ 5, 13, 21],
[ 6, 14, 22],
[ 7, 15, 23]])
>>> c.shape
(8, 3)
>>> b.T #T属性就是让数组形状倒置 b.T与np.transpose(b)是相等的
array([[ 0, 8, 16],
[ 1, 9, 17],
[ 2, 10, 18],
[ 3, 11, 19],
[ 4, 12, 20],
[ 5, 13, 21],
[ 6, 14, 22],
[ 7, 15, 23]])
>>> d = a.reshape(2, 3, 4)
>>> d
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]]])
>>> e = np.transpose(d) #transpose倒置数组的形状从(2, 3, 4)到(4, 3, 2)
>>> e
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]]])
>>> e.shape
(4, 3, 2)
>>> d.T #同理d.T与np.transpose(d)是相等的
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]]])
>>> f = np.transpose(d, (1, 0, 2)) #同时,transpose还可以指定倒置的方法,(1, 0, 2)是指把d的形状(2, 3, 4)按照索引元组(1, 0, 2)倒置及倒置后为形状为(3, 2, 4)
>>> f
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]]])
>>> f.shape
(3, 2, 4)
>>> d.reshape(3, 2, 4) #但是倒置的形状并不是源数组的reshape, d.reshape(3,2,4) != np.transpose(d, (1, 0, 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]]])
>>> g = d.swapaxes(0, 1) #函数swapaxes指定两个维度的倒置,从d的(2, 3, 4)倒置(0, 1), 倒置后为(3, 2, 4)
>>> g
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]]])
>>> h = np.swapaxes(d, 0, 1) #或者这样的写法也可以
>>> h
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]]])
>>> i = d.swapaxes(1, 2) #119,120行的结果也是一样的
>>> j = d.transpose(0, 2, 1)
>>> i
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]]])
>>> j
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]]])
>>> i.shape
(2, 4, 3)
>>> j.shape
(2, 4, 3)
>>>

2.14 empty_like, ones_like, zeros_like, full_like, empty

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
>>> a
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])
>>> a = a.reshape((2, 3, 4))
>>> a
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 = np.empty_like(a) #生成一个与a同一形状的随机数组
>>> b
array([[[ 87213328, 4304144, 1667845468, 1869836146],
[1130132582, 1953528178, 1634887535, 1551460464],
[1634100548, 1937009781, 1869762652, 1701079414]],

[[1766677618, 1936683619, 544499311, 1869771859],
[1126197102, 1953528178, 1634887535, 1667852400],
[1869762592, 1701079414, 738197618, 1141389320]]])
>>> c = np.ones_like(a) #生成一个同a形状的由1组成的数组
>>> c
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]]])
>>> d = np.zeros_like(a) #生成一个同a形状的由0组成的数组
>>> d
array([[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]],

[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]])
>>> e = np.full_like(a, 8) #生成一个同a形状,指定参数组成的数组
>>> e
array([[[8, 8, 8, 8],
[8, 8, 8, 8],
[8, 8, 8, 8]],

[[8, 8, 8, 8],
[8, 8, 8, 8],
[8, 8, 8, 8]]])
>>> e = np.full_like(a, True)
>>> e
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]]])
>>> e = np.full_like(a, False)
>>> e
array([[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]],

[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]])
>>> np.empty([2, 3]) #生成一个指定形状,指定数据类型的的随机,随机数组
array([[2.67276450e+185, 1.69506143e+190, 1.75184137e+190],
[9.48819320e+077, 1.63730399e-306, 0.00000000e+000]])
>>> np.empty([2, 2], dtype = int)
array([[1734934692, 1912645992],
[ 50, 977492218]])
>>> np.empty([2, 2], dtype = int)
array([[167, 1],
[ 0, 0]])

2.15 numpy.tile(A, reps)

把数组A沿着指定的维度方向复制,reps是一个元组或者整数

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
>>> a
array([[0, 1, 2],
[3, 4, 5]])
>>> b = np.tile(a, 2) #一维(x轴)的方向的两倍, 从(2, 3)变为(2, 6)
>>> b
array([[0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5]])
>>> c = np.tile(a, (2, 1)) #先x轴一倍(及不变),再y轴两倍,从(2, 3)变为(4, 3)
>>> c
array([[0, 1, 2],
[3, 4, 5],
[0, 1, 2],
[3, 4, 5]])
>>> d = np.tile(a, (1, 2, 3)) #x轴3倍, y轴2倍, z轴1倍
>>> d
array([[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]]])
>>> e = np.tile(a, 3) # x轴3倍,from a (2, 3) to e (2, 9)
>>> e
array([[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]])
>>> f = np.tile(e, (2, 1)) #y轴2倍, from e (2, 9) to f (4, 9)
>>> f
array([[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]])
>>> f.shape
(4, 9)
>>> g = np.tile(f, (1, 1, 1)) # z轴1倍,from f (4, 9) to g (1, 4, 9)
>>> g
array([[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]]])
>>> g.shape
(1, 4, 9)
>>> h = np.tile(a, (2, 2, 3)) # from a (2, 3) to h (2, 4, 9)
>>> h
array([[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]],

[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]]])
>>> i = np.tile(f, (2, 1, 1)) # from f (4, 9) to i (2, 4, 9) 等于h = np.tile(a, (2, 2, 3))
>>> i
array([[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]],

[[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5],
[0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5]]])
>>> h.shape
(2, 4, 9)
>>> i.shape
(2, 4, 9)
>>>

2.16 广播 broadcasting

理解了2.15, tile函数后,理解广播的规则就简单了

两个数组广播的规则是:

  1. 如果数组不具有相同的rank,则将较低等级数组的形状添加1,直到两个形状具有相同的长度。
  2. 如果两个数组在维度上具有相同的大小,或者如果其中一个数组在该维度中的大小为1,则称这两个数组在维度上是兼容的。
  3. 如果数组在所有维度上兼容,则可以一起广播。
  4. 广播之后,每个阵列的行为就好像它的形状等于两个输入数组的形状的元素最大值。
  5. 在一个数组的大小为1且另一个数组的大小大于1的任何维度中,第一个数组的行为就像沿着该维度复制一样

看例子:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
>>> import numpy as np
>>> a = np.arange(9)
>>> a = a.reshape(3, 3)
>>> b = np.arange(6)
>>> b = b.reshape(2, 3, 1)
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> a.shape #我们可以理解为3x3,
(3, 3)
>>> b
array([[[0],
[1],
[2]],

[[3],
[4],
[5]]])
>>> b.shape #我们可以理解为2x3x1
(2, 3, 1)
#当a(2维),b(3维)规则1,两个数组进行广播时,不具有相同的维度,较低等级数组a的形状添加1,及理解为a:1x3x3
#规则2,a:1x3x3, b:2x3x1,a,b在y轴上都为3,这个维度上具有相同的大小,或者a,b在x轴上分别为3和1,在z轴上分别为1和2,其中都有一个数组维度的大小为1,这样就成为两个数组在维度上是兼容的。
#规则3 a,b符合广播的条件
#规则4 a:1x3x3, b:2x3x1 在广播时,每个轴上取最大值,x轴取3,y轴取3,z轴取2,则a,b广播后的形状是2x3x3,(2, 3, 3)
>>> c = a + b
>>> c # c就是广播后的结果,不光是加,减法,乘除等都符合这一规则
array([[[ 0, 1, 2],
[ 4, 5, 6],
[ 8, 9, 10]],

[[ 3, 4, 5],
[ 7, 8, 9],
[11, 12, 13]]])
>>> c.shape
(2, 3, 3)
#下面是运算过程
#规则5 a:1x3x3, b:2x3x1,c:2x3x3,实际上我们看到每个轴上取最大值,那么对应较小(为1)的维度就要复制为最大值的大小。看下面详细解释
>>> d = np.tile(a, (2, 1, 1)) #取最大值后(广播后)为2x3x3,那么a:1x3x3就要在z轴上复制为它的2倍,我们可以用tile函数进行复制
>>> d
array([[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]],

[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]])
>>> e = np.tile(b, 3) #同理 b:2x3x1,广播后为2x3x3,及b在x轴上复制为3倍
>>> e
array([[[0, 0, 0],
[1, 1, 1],
[2, 2, 2]],

[[3, 3, 3],
[4, 4, 4],
[5, 5, 5]]])
>>> f = d + e #实际上a,b的运算就是d与e的运算。注意这里不是dot()的运算方法
>>> f
array([[[ 0, 1, 2],
[ 4, 5, 6],
[ 8, 9, 10]],

[[ 3, 4, 5],
[ 7, 8, 9],
[11, 12, 13]]])
>>> f.shape
(2, 3, 3)
>>>