数组形状

In [1]:

  1. %pylab
  1. Using matplotlib backend: Qt4Agg
  2. Populating the interactive namespace from numpy and matplotlib

修改数组的形状

In [2]:

  1. a = arange(6)
  2. a

Out[2]:

  1. array([0, 1, 2, 3, 4, 5])

将形状修改为2乘3:

In [3]:

  1. a.shape = 2,3
  2. a

Out[3]:

  1. array([[0, 1, 2],
  2. [3, 4, 5]])

与之对应的方法是 reshape ,但它不会修改原来数组的值,而是返回一个新的数组:

In [4]:

  1. a.reshape(3,2)

Out[4]:

  1. array([[0, 1],
  2. [2, 3],
  3. [4, 5]])

In [5]:

  1. a

Out[5]:

  1. array([[0, 1, 2],
  2. [3, 4, 5]])

shapereshape 方法不能改变数组中元素的总数,否则会报错:

In [6]:

  1. a.reshape(4,2)
  1. ---------------------------------------------------------------------------
  2. ValueError Traceback (most recent call last)
  3. <ipython-input-6-1a35a76a1693> in <module>()
  4. ----> 1 a.reshape(4,2)
  5.  
  6. ValueError: total size of new array must be unchanged

使用 newaxis 增加数组维数

In [7]:

  1. a = arange(3)
  2. shape(a)

Out[7]:

  1. (3L,)

In [8]:

  1. y = a[newaxis, :]
  2. shape(y)

Out[8]:

  1. (1L, 3L)

根据插入位置的不同,可以返回不同形状的数组:

In [9]:

  1. y = a[:, newaxis]
  2. shape(y)

Out[9]:

  1. (3L, 1L)

插入多个新维度:

In [10]:

  1. y = a[newaxis, newaxis, :]
  2. shape(y)

Out[10]:

  1. (1L, 1L, 3L)

squeeze 方法去除多余的轴

In [11]:

  1. a = arange(6)
  2. a.shape = (2,1,3)

In [12]:

  1. b = a.squeeze()
  2. b.shape

Out[12]:

  1. (2L, 3L)

squeeze 返回一个将所有长度为1的维度去除的新数组。

数组转置

使用 transpose 返回数组的转置,本质上是将所有维度反过来:

In [13]:

  1. a

Out[13]:

  1. array([[[0, 1, 2]],
  2.  
  3. [[3, 4, 5]]])

对于二维数组,这相当于交换行和列:

In [14]:

  1. a.transpose()

Out[14]:

  1. array([[[0, 3]],
  2.  
  3. [[1, 4]],
  4.  
  5. [[2, 5]]])

或者使用缩写属性:

In [15]:

  1. a.T

Out[15]:

  1. array([[[0, 3]],
  2.  
  3. [[1, 4]],
  4.  
  5. [[2, 5]]])

注意:

  • 对于复数数组,转置并不返回复共轭,只是单纯的交换轴的位置
  • 转置可以作用于多维数组

In [16]:

  1. a = arange(60)
  2. a

Out[16]:

  1. array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  2. 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
  3. 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
  4. 51, 52, 53, 54, 55, 56, 57, 58, 59])

In [17]:

  1. a.shape = 3,4,5
  2. a

Out[17]:

  1. array([[[ 0, 1, 2, 3, 4],
  2. [ 5, 6, 7, 8, 9],
  3. [10, 11, 12, 13, 14],
  4. [15, 16, 17, 18, 19]],
  5.  
  6. [[20, 21, 22, 23, 24],
  7. [25, 26, 27, 28, 29],
  8. [30, 31, 32, 33, 34],
  9. [35, 36, 37, 38, 39]],
  10.  
  11. [[40, 41, 42, 43, 44],
  12. [45, 46, 47, 48, 49],
  13. [50, 51, 52, 53, 54],
  14. [55, 56, 57, 58, 59]]])

In [18]:

  1. b = a.T
  2. b.shape

Out[18]:

  1. (5L, 4L, 3L)

转置只是交换了轴的位置。

另一方面,转置返回的是对原数组的另一种view,所以改变转置会改变原来数组的值。

In [19]:

  1. a = arange(6)
  2. a.shape = (2,3)
  3. a

Out[19]:

  1. array([[0, 1, 2],
  2. [3, 4, 5]])

修改转置:

In [20]:

  1. b = a.T
  2. b[0,1] = 30

原数组的值也改变:

In [21]:

  1. a

Out[21]:

  1. array([[ 0, 1, 2],
  2. [30, 4, 5]])

数组连接

有时我们需要将不同的数组按照一定的顺序连接起来:

  1. concatenate((a0,a1,...,aN), axis=0)

注意,这些数组要用 () 包括到一个元组中去。

除了给定的轴外,这些数组其他轴的长度必须是一样的。

In [22]:

  1. x = array([
  2. [0,1,2],
  3. [10,11,12]
  4. ])
  5. y = array([
  6. [50,51,52],
  7. [60,61,62]
  8. ])
  9. print x.shape
  10. print y.shape
  1. (2L, 3L)
  2. (2L, 3L)

默认沿着第一维进行连接:

In [23]:

  1. z = concatenate((x,y))
  2. z

Out[23]:

  1. array([[ 0, 1, 2],
  2. [10, 11, 12],
  3. [50, 51, 52],
  4. [60, 61, 62]])

In [24]:

  1. z.shape

Out[24]:

  1. (4L, 3L)

沿着第二维进行连接:

In [25]:

  1. z = concatenate((x,y), axis=1)
  2. z

Out[25]:

  1. array([[ 0, 1, 2, 50, 51, 52],
  2. [10, 11, 12, 60, 61, 62]])

In [26]:

  1. z.shape

Out[26]:

  1. (2L, 6L)

注意到这里 xy 的形状是一样的,还可以将它们连接成三维的数组,但是 concatenate 不能提供这样的功能,不过可以这样:

In [27]:

  1. z = array((x,y))

In [28]:

  1. z.shape

Out[28]:

  1. (2L, 2L, 3L)

事实上,Numpy提供了分别对应这三种情况的函数:

  • vstack
  • hstack
  • dstack

In [29]:

  1. vstack((x, y)).shape

Out[29]:

  1. (4L, 3L)

In [30]:

  1. hstack((x, y)).shape

Out[30]:

  1. (2L, 6L)

In [31]:

  1. dstack((x, y)).shape

Out[31]:

  1. (2L, 3L, 2L)

Flatten 数组

flatten 方法的作用是将多维数组转化为1维数组:

In [32]:

  1. a = array([[0,1],
  2. [2,3]])
  3. b = a.flatten()
  4. b

Out[32]:

  1. array([0, 1, 2, 3])

返回的是数组的复制,因此,改变 b 并不会影响 a 的值:

In [33]:

  1. b[0] = 10
  2. print b
  3. print a
  1. [10 1 2 3]
  2. [[0 1]
  3. [2 3]]

flat 属性

还可以使用数组自带的 flat 属性:

In [34]:

  1. a.flat

Out[34]:

  1. <numpy.flatiter at 0x3d546a0>

a.flat 相当于返回了所有元组组成的一个迭代器:

In [35]:

  1. b = a.flat

In [36]:

  1. b[0]

Out[36]:

  1. 0

但此时修改 b 的值会影响 a

In [37]:

  1. b[0] = 10
  2. print a
  1. [[10 1]
  2. [ 2 3]]

In [38]:

  1. a.flat[:]

Out[38]:

  1. array([10, 1, 2, 3])

ravel 方法

除此之外,还可以使用 ravel 方法,ravel 使用高效的表示方式:

In [39]:

  1. a = array([[0,1],
  2. [2,3]])
  3. b = a.ravel()
  4. b

Out[39]:

  1. array([0, 1, 2, 3])

修改 b 会改变 a

In [40]:

  1. b[0] = 10
  2. a

Out[40]:

  1. array([[10, 1],
  2. [ 2, 3]])

但另一种情况下:

In [41]:

  1. a = array([[0,1],
  2. [2,3]])
  3. aa = a.transpose()
  4. b = aa.ravel()
  5. b

Out[41]:

  1. array([0, 2, 1, 3])

In [42]:

  1. b[0] = 10

In [43]:

  1. aa

Out[43]:

  1. array([[0, 2],
  2. [1, 3]])

In [44]:

  1. a

Out[44]:

  1. array([[0, 1],
  2. [2, 3]])

可以看到,在这种情况下,修改 b 并不会改变 aa 的值,原因是我们用来 ravel 的对象 aa 本身是 a 的一个view。

atleast_xd 函数

保证数组至少有 x 维:

In [45]:

  1. x = 1
  2. atleast_1d(x)

Out[45]:

  1. array([1])

In [46]:

  1. a = array([1,2,3])
  2. b = atleast_2d(a)
  3. b.shape

Out[46]:

  1. (1L, 3L)

In [47]:

  1. b

Out[47]:

  1. array([[1, 2, 3]])

In [48]:

  1. c = atleast_3d(b)

In [49]:

  1. c.shape

Out[49]:

  1. (1L, 3L, 1L)

x 可以取值 1,2,3。

Scipy库中,这些函数被用来保证输入满足一定的条件:“

用法 Scipy中出现次数
value.flaten() value.flat value.ravel() ~2000次
atleast_1d(value) atleast_2d(value) ~700次
asarray(value) ~4000次

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/03-numpy/03.07-array-shapes.ipynb