Numpy快速入门(三)——数组进阶操作

目录

  • 一、改变数组的形状
    • 1.1 np.reshape()
    • 1.2 np.ravel()
    • 1.3 np.flatten()
  • 二、(类)转置操作
    • 2.1 ndarray.T
    • 2.2 np.swapaxes()
    • 2.3 np.moveaxis()
  • 三、合并数组
    • 3.1 np.concatenate()
    • 3.2 np.stack()
    • 3.3 np.block()
    • 3.3 np.vstack()
    • 3.4 np.hstack()
  • 四、划分数组
    • 4.1 np.split()
    • 4.2 np.array_split()
    • 4.3 np.vsplit()
    • 4.4 np.hsplit()
  • 五、反转数组
    • 5.1 np.flip()
    • 5.2 np.fliplr()
    • 5.3 np.flipud()

一、改变数组的形状

函数 作用
np.reshape(a, newshape) a是数组,newshape是整型元组;返回newshape形状的数组
np.ravel(a) 展平成一维数组;等价于np.reshape(a, -1)
np.flatten(a) 效果和ravel一样,但更推荐使用flatten

1.1 np.reshape()

A = np.arange(6).reshape((2, 3))
print(A)
# [[0 1 2]
#  [3 4 5]]

事实上元组的括号可以省略,即我们可以更简洁地使用reshape:

A = np.arange(6).reshape(2, 3)

newshape 中的某一个分量可以为-1,reshape会根据其他分量自动推算:

A = np.arange(6).reshape(2, -1)
print(A)
# [[0 1 2]
#  [3 4 5]]

若 newshape = -1,那么reshape会将其展平为一维数组

A = np.arange(6).reshape(6).reshape(-1)
print(A)
# [0 1 2 3 4 5]

1.2 np.ravel()

A = np.arange(8).reshape(2, 2, 2).ravel()
print(A)
# [0 1 2 3 4 5 6 7]

1.3 np.flatten()

A = np.arange(8).reshape(2, 2, 2).flatten()
print(A)
# [0 1 2 3 4 5 6 7]

可以看出flatten的效果和ravel一样,那使用哪一个更好呢?

直接说答案:使用flatten更好,具体原因见博客。

二、(类)转置操作

函数 作用
ndarray.T 转置一个数组,即反转shape
np.swapaxes(a, axis1, axis2) 交换数组的两个轴
np.moveaxis(a, s, d) s 和 d 是整数整型列表;将索引为 s 的轴移动到索引 d 处

2.1 ndarray.T

A = np.arange(6).reshape(2, 3)
print(A)
print(A.T)
# [[0 1 2]
#  [3 4 5]]
# [[0 3]
#  [1 4]
#  [2 5]]

但要注意,ndarray.T 无法转置一维数组

A = np.arange(6)
print(A)
print(A.T)
# [0 1 2 3 4 5]
# [0 1 2 3 4 5]

那我们该如何转置一维数组呢?有以下几种方法:

方法一:先转换为二维数组

将 ndarray 变成二维数组再进行转置:

A = np.arange(4)
A = np.array([A])
print(A.T)
# [[0]
#  [1]
#  [2]
#  [3]]

当然也可以使用 np.transpose(),它与 ndarray.T 等价:

A = np.arange(4)
print(np.transpose([A]))
# [[0]
#  [1]
#  [2]
#  [3]]

方法二:使用reshape函数

A = np.arange(4)
A = A.reshape(len(A), -1)  # 第二个参数改为1也可以
print(A)
# [[0]
#  [1]
#  [2]
#  [3]]

方法三:使用newaxis

我们在本系列的第一篇文章中提到了 np.newaxis,这里我们将进一步讲解它的用法.

newaxis 的本质是 None:

print(np.newaxis == None)
# True

正如其名,将 newaxis 和 切片结合起来使用可以为数组添加一个新的维度),它能将一维数组变为二维数组,将二维数组变为三维数组,也可以直接将一维数组变为三维数组等。

巧记: newaxis 位于哪一轴,则得到的结果沿该轴的长度就为1

可能不太好理解,这里举几个例子。假设 A 是一个长度为3的一维数组,则:

  • A[np.newaxis, :] : newaxis位于第一个轴,则得到的结果是一个 1 × 3 1\times 3 1×3 的数组。
  • A[:, np.newaxis] : newaxis位于第二个轴,则得到的结果是一个 3 × 1 3\times1 3×1 的数组。
  • A[:, np.newaxis, np.newaxis] : newaxis位于第二个轴和第三个轴,则得到的结果是一个 3 × 1 × 1 3\times1\times1 3×1×1 的数组。

我们再举几个例子并结合shape方法来进一步说明 newaxis 的效果。

首先创建一个 3 × 4 3\times4 3×4 的数组:

A = np.arange(12).reshape(3, 4)
print(A.shape)
# (3, 4)

然后使用 newaxis 添加新的轴:

print(A[:, :, np.newaxis].shape)
print(A[:, np.newaxis, :].shape)
print(A[np.newaxis, :, :].shape)
print(A[np.newaxis, np.newaxis, :, :].shape)
# (3, 4, 1)
# (3, 1, 4)
# (1, 3, 4)
# (1, 1, 3, 4)

看完这些例子,相信你对 newaxis 已经有了一个基本的认知,那如何转置一个维数组也不再是难事了。

因为转置后的一维数组一定是形如 a × 1 a\times 1 a×1 的形状,因此 newaxis 一定位于第二个轴,所以只需要 A[:, np.newaxis] 即可转置:

A = np.arange(4)
print(A[:, np.newaxis])
# [[0]
#  [1]
#  [2]
#  [3]]

2.2 np.swapaxes()

A = np.zeros((3, 4, 5))
print(A.shape)
# (3, 4, 5)
print(np.swapaxes(A, 0, 1).shape)
print(np.swapaxes(A, 0, 2).shape)
print(np.swapaxes(A, 1, 2).shape)
# (4, 3, 5)
# (5, 4, 3)
# (3, 5, 4)

2.3 np.moveaxis()

s 和 d 都为整数时:

A = np.zeros((3, 4, 5))
print(np.moveaxis(A, 0, 2).shape)
print(np.moveaxis(A, 0, -1).shape)
print(np.moveaxis(A, -1, -2).shape)
# (4, 5, 3)
# (4, 5, 3)
# (3, 5, 4)

s 和 d 都为整型列表时:

A = np.zeros((3, 4, 5))
print(np.moveaxis(A, [0, 1], [1, 2]).shape)
print(np.moveaxis(A, [0, 1], [0, 2]).shape)
print(np.moveaxis(A, [1, 0], [0, 2]).shape)
# (5, 3, 4)
# (3, 5, 4)
# (4, 5, 3)

三、合并数组

函数 作用
np.concatenate((a1, a2, …), axis=0) a1, a2等是数组,axis控制连接的方向;用于将多个数组连接在一起,当axis为None时,会在连接之前压平将要连接的各个数组
np.stack(arrays, axis=0) arrays是由数组组成的列表或元组;沿axis方向堆叠这些数组
np.block(arrays) 将若干个数组组合在一起构成一个新数组;常用于构建分块矩阵
np.vstack((a1, a2, …)) 垂直堆叠数组
np.hstack((a1, a2, …)) 水平堆叠数组

3.1 np.concatenate()

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print(np.concatenate((a, b), axis=0))
# [[1 2]
#  [3 4]
#  [5 6]]
print(np.concatenate((a, b.T), axis=1))
# [[1 2 5]
#  [3 4 6]]
print(np.concatenate((a, b), axis=None))
# [1 2 3 4 5 6]

若要连接两个一维数组,只需要:

a = np.array([1, 2])
b = np.array([3, 4])
print(np.concatenate((a, b)))
# [1 2 3 4]

3.2 np.stack()

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.stack((a, b)))
# [[1 2 3]
#  [4 5 6]]
print(np.stack((a, b), axis=1))
# [[1 4]
#  [2 5]
#  [3 6]]
arrays = [np.zeros((2, 3)) for _ in range(4)]
print(np.stack(arrays, axis=0).shape)
print(np.stack(arrays, axis=1).shape)
print(np.stack(arrays, axis=2).shape)
# (4, 2, 3)
# (2, 4, 3)
# (2, 3, 4)

注意到 axis=2 实际上就是最后一个轴,我们也可以用 axis=-1 来代替它,效果是一样的,其他轴也可以此类推:

print(np.stack(arrays, axis=-3).shape)
print(np.stack(arrays, axis=-2).shape)
print(np.stack(arrays, axis=-1).shape)
# (4, 2, 3)
# (2, 4, 3)
# (2, 3, 4)

3.3 np.block()

A = np.eye(2) * 2
B = np.eye(3) * 3
C = np.block([
		  [A,               np.zeros((2, 3))], 
          [np.ones((3, 2)), B               ]
    ])
print(C)
# [[2. 0. 0. 0. 0.]
#  [0. 2. 0. 0. 0.]
#  [1. 1. 3. 0. 0.]
#  [1. 1. 0. 3. 0.]
#  [1. 1. 0. 0. 3.]]

3.3 np.vstack()

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.vstack((a, b)))
# [[1 2 3]
#  [4 5 6]]

更形象的解释:因为是垂直堆叠,所以把 B B B 放在 A A A 下面

A = [ 1 , 2 , 3 ] , B = [ 4 , 5 , 6 ] A=[1, 2, 3],\quad B=[4,5,6] A=[1,2,3],B=[4,5,6]

a = np.array([[1], [2], [3]])
b = np.array([[4], [5], [6]])
print(np.vstack((a, b)))
# [[1]
#  [2]
#  [3]
#  [4]
#  [5]
#  [6]]

同理把 B B B 放在 A A A 下面

A = [ 1 2 3 ] , B = [ 4 5 6 ] A=\begin{bmatrix} 1 \\ 2\\ 3 \\ \end{bmatrix} ,\quad B=\begin{bmatrix} 4 \\ 5\\ 6 \\ \end{bmatrix} A=123,B=456

3.4 np.hstack()

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.hstack((a, b)))
# [1 2 3 4 5 6]

更形象的解释:因为是水平堆叠,所以把 B B B 放在 A A A 右边

A = [ 1 , 2 , 3 ] , B = [ 4 , 5 , 6 ] A=[1, 2, 3],\quad B=[4,5,6] A=[1,2,3],B=[4,5,6]

a = np.array([[1], [2], [3]])
b = np.array([[4], [5], [6]])
print(np.hstack((a, b)))
# [[1 4]
#  [2 5]
#  [3 6]]

同理把 B B B 放在 A A A 右边

A = [ 1 2 3 ] , B = [ 4 5 6 ] A=\begin{bmatrix} 1 \\ 2\\ 3 \\ \end{bmatrix} ,\quad B=\begin{bmatrix} 4 \\ 5\\ 6 \\ \end{bmatrix} A=123,B=456

四、划分数组

函数 作用
np.split(a, indices/sections) 将数组a划分成一些子数组并以列表形式返回;sections是子数组的数量,indices是索引列表;可以按照数量划分也可以按照索引位置划分
np.array_split(a, indices/sections) 与split的唯一区别在于,当选择数量划分时,不必要求每个子数组的形状相同
np.vsplit(a, indices/sections) 垂直划分数组
np.hsplit(a, indices/sections) 水平划分数组

4.1 np.split()

按照数量划分,每个子数组的形状相同

a = np.arange(9)
print(np.split(a, 3))
# [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
print(np.split(a, 4))
# ValueError: array split does not result in an equal division

报错的原因是因为你无法将长度为9的数组四等分。

当然我们也可以按照索引进行划分:

a = np.arange(9)
print(np.split(a, [2, 5]))
# [array([0, 1]), array([2, 3, 4]), array([5, 6, 7, 8])]
print(np.split(a, [1, 3, 5, 7]))
# [array([0]), array([1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]

4.2 np.array_split()

a = np.arange(9)
print(np.array_split(a, 4))
# [array([0, 1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]

4.3 np.vsplit()

按数量划分:

a = np.arange(16).reshape(4, 4)
print(np.vsplit(a, 2))
# [array([[0, 1, 2, 3],
#        [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
#        [12, 13, 14, 15]])]

按索引划分:

a = np.arange(16).reshape(4, 4)
print(np.vsplit(a, [1, 2]))
# [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
#        [12, 13, 14, 15]])]

当数组的维度大于等于3时,划分方向仍沿第一个轴(行)

a = np.arange(8).reshape(2, 2, 2)
print(np.vsplit(a, 2))
# [array([[[0, 1],
#         [2, 3]]]), array([[[4, 5],
#         [6, 7]]])]

4.4 np.hsplit()

按数量划分:

a = np.arange(16).reshape(4, 4)
print(np.hsplit(a, 2))
# [array([[ 0,  1],
#        [ 4,  5],
#        [ 8,  9],
#        [12, 13]]), array([[ 2,  3],
#        [ 6,  7],
#        [10, 11],
 #       [14, 15]])]

按索引划分:

a = np.arange(16).reshape(4, 4)
print(np.hsplit(a, [1, 2]))
# [array([[ 0],
#        [ 4],
#        [ 8],
#        [12]]), array([[ 1],
#        [ 5],
#        [ 9],
#        [13]]), array([[ 2,  3],
#        [ 6,  7],
#        [10, 11],
#        [14, 15]])]

当数组的维度大于等于3时,划分方向仍沿第二个轴(列)

a = np.arange(8).reshape(2, 2, 2)
print(np.hsplit(a, 2))
# [array([[[0, 1]],

#        [[4, 5]]]), array([[[2, 3]],

#        [[6, 7]]])]

五、反转数组

函数 作用
np.flip(a, axis=None) 沿axis方向反转数组a;axis为整数整型元组;当axis为None,会将数组沿所有的轴进行反转。当axis为元组时,会将数组沿元组中提到的轴进行反转
np.fliplr(a) 沿第二个轴(列方向)进行反转
np.flipud(a) 沿第一个轴(行方向)进行反转

5.1 np.flip()

先考虑一维数组:

a = np.arange(6)
print(np.flip(a))
# [5 4 3 2 1 0]

对于二维数组:

A = np.arange(8).reshape(2, 2, 2)
print(A)
# [[[0 1]
#   [2 3]]
# 
#  [[4 5]
#   [6 7]]]
print(np.flip(A, axis=0))
# [[[4 5]
#   [6 7]]
# 
#  [[0 1]
#   [2 3]]]
print(np.flip(A, axis=1))
# [[[2 3]
#   [0 1]]
# 
#  [[6 7]
#   [4 5]]]
print(np.flip(A, axis=2))
# [[[1 0]
#   [3 2]]
# 
#  [[5 4]
#   [7 6]]]
print(np.flip(A))
# [[[7 6]
#   [5 4]]
# 
#  [[3 2]
#   [1 0]]]
print(np.flip(A, axis=(0, 2)))
# [[[5 4]
#   [7 6]]
# 
#  [[1 0]
#   [3 2]]]

5.2 np.fliplr()

A = np.diag([1, 2, 3])
print(np.fliplr(A))
# [[0 0 1]
#  [0 2 0]
#  [3 0 0]]

5.3 np.flipud()

A = np.diag([1, 2, 3])
print(np.flipud(A))
# [[0 0 3]
#  [0 2 0]
#  [1 0 0]]

现在,我们可以对flip()函数作一个总结:

  • flip(a, 0) 等价于 flipud(a)
  • flip(a, 1) 等价于 fliplr(a)
  • flip(a, n) 等价于 a[..., ::-1, ...],其中 ::-1 的索引为 n
  • flip(a) 等价于 a[::-1, ::-1, ..., ::-1],其中所有位置上均是 ::-1
  • flip(a, (0, 1)) 等价于 a[::-1, ::-1, ...],只有索引 01 处是 ::-1

你可能感兴趣的:(数据分析,python,数组,数据分析)