0%

NumPy学习笔记-1-基础

NumPy,整个Python数据科学工具生态系统的核心。

NumPy,是Numerical Python的简称,提供了高效存储和操作密集数据缓存的接口。在某些方面,NumPy数据与Python内置的列表类型非常相似。但是随着数组在维度上变大,NumPy数组提供了更加高效的存储和数据操作。NumPy数组几乎是整个Python数据科学工具生态系统的核心。 因此,不管你对数据科学的哪个方面感兴趣,花点时间学习如何有效地使用NumPy都是非常值得的。

在开始学习NumPy之前,需要先理解NumPy的优势,这涉及到数据是如何被存储和操作的。标准的Python语言是用C语言编写的。这意味着每一个Python对象都是一个聪明的伪C语言结构体,该结构体不仅包含其值,还有其他信息。例如,当我们在Python中定义一个整型,如 x = 10,这里x并不是一个“原生”整型,而是一个指针,指向一个C语言的复合结构体,这个结构体包含内存位置、可以转换成整型的字节等大量额外的信息。正是由于这些大量额外的信息,Python可以自由、动态的编码。但这些额外信息也成为其负担,在多个对象组合的结构体中尤其明显。Python中标准可变的元素容器是列表,列表是灵活的,因为一个列表中既可以包含同一种类型元素,也可以包含不同类型。为了获得这些灵活的类型,列表中的每一项必须包含各自的类型信息、引用计数和其他信息;也就是说,每一项都是一个完整的Python对象。如果列表中的所有变量都是同一类型的,那么很多信息都会显得多余,这时候,把数据存储在固定类型的数组中会更高效。NumPy就是一种固定类型的数组,它要求数组必须包含同一类型的数据,虽然这样失去了灵活性,但可以更有效地存储和操作数据。

NumPy并非Python内置模块,因此在使用前需要先导入,一般使用np作为NumPy的别名:

1
import numpy as np

1 创建数组

创建数组经常使用的函数有np.array()np.reshape()np.arange()np.linspace()np.logspace()np.random()np.ones()np.ones_like()np.zeros()np.zeros_like()np.empty()np.empty_like()np.full()np.full_like()np.eye() 等。

1.1 np.array()np.reshape()

  • np.array()

是创建数据最常用的函数,完整函数和参数为:np.array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0) 其中,object只能是列表或元组,dtype决定数据类型,ndim表示数组的维度;copy、order、subok三个参数并不常用,暂时不深入学习。

1
2
3
4
5
a = np.array([1, 4, 2, 3])
print('a:', a, a.dtype)

b = np.array((2.2, 5.0, 7.1, 6.6))
print('b:', b, b.dtype)
a: [1 4 2 3] int32
b: [2.2 5.  7.1 6.6] float64

注意: 根据前面的介绍可知,不同于Python列表,NumPy要求数组必须包含同一类型的数据。如果类型不匹配,NumPy将会向上转换为同一类型数据(如果可行)。在下面这个例子中,整型被转换为浮点型:

1
2
a = np.array([1, 4, 2.0, 5, 3])
print('a:', a, a.dtype)
a: [1. 4. 2. 5. 3.] float64

NumPy数组可以是一维的、二维的,也可以是多维的。数组的维度一般用ndim函数,形状用shape函数,此外还有大小size 、数据类型dtype 等。

1
2
3
# 一维数组
a = np.array([1, 2, 3, 4])
print('a:\n', a, '\na_nidm:', a.ndim, '\na_shape:', a.shape)
a:
 [1 2 3 4] 
a_nidm: 1 
a_shape: (4,)
1
2
3
4
5
6
# 二维数组,三行四列

b = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
print('b:\n', b, '\nb_nidm:', b.ndim, '\nb_shape:', b.shape)
b:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]] 
b_nidm: 2 
b_shape: (3, 4)
1
2
3
4
5
6
# 三维数组,三个二行四列的数组

c = np.array([[[1, 2, 3, 4], [5, 6, 7, 8]],
[[9, 10, 11, 12], [13, 14, 15, 16]],
[[17, 18, 19, 20], [21, 22, 23, 24]]])
print('c:\n', c, '\nc_nidm:', c.ndim, '\nc_shape:', c.shape)
c:
 [[[ 1  2  3  4]
  [ 5  6  7  8]]

 [[ 9 10 11 12]
  [13 14 15 16]]

 [[17 18 19 20]
  [21 22 23 24]]] 
c_nidm: 3 
c_shape: (3, 2, 4)
  • np.reshape

np.reshape(a, newshape, order='C') 返回一个数组a的新形状,但不改变其数据。此函数一般用于数组的变形,较为常用。

1
2
3
4
5
6
7
data = [i for i in range(1, 13)]

a = np.array(data)
print('a:\n', a)

b = np.reshape(a, (3, 4))
print('b:\n', b)
a:
 [ 1  2  3  4  5  6  7  8  9 10 11 12]
b:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
1
2
3
4
# 直接在创建数组时使用reshape

c = np.array(data).reshape(3, 4)
print('c:\n', c)
c:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]

1.2 创建规律性数组

通过使用函数,可以快速创建具有规律性的数组,最常用的三个函数就是np.arange()np.linspace()np.logspace()

  • np.arange()

np.arange() 与Python中的arange()用法相似,但可以生成浮点数,完整函数与参数为:arange(start, stop, step, dtype=None)

1
2
3
4
5
a = np.arange(5)
print('a:', a, a.dtype)

b = np.arange(1, 5, 0.5)
print('b:', b, b.dtype)
a: [0 1 2 3 4] int32
b: [1.  1.5 2.  2.5 3.  3.5 4.  4.5] float64
  • np.linspace()

np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0) 该函数返回一个等差数列。数列范围为“[start, stop]”,数据数量由参数“num”决定,区间结束端点“stop”默认包含其中,也可由参数“endpoint”更改。参数“retstep”决定是否返回等差值。

1
2
3
4
5
6
7
8
9
10
# 在[2,3]的闭区间内生成5个等间隔数据
a = np.linspace(2.0, 3.0, num=5)

# 在[2,3)的左开右闭区间内生成5个等间隔数据
b = np.linspace(2.0, 3.0, num=5, endpoint=False)

# 在[2,3]的闭区间内生成5个等间隔数据,并返回间隔值
c = np.linspace(2.0, 3.0, num=5, retstep=True)

print('a:', a, '\nb:', b, '\nc:', c)
a: [2.   2.25 2.5  2.75 3.  ] 
b: [2.  2.2 2.4 2.6 2.8] 
c: (array([2.  , 2.25, 2.5 , 2.75, 3.  ]), 0.25)
  • np.logspace()

np.logspace(start,stop,num=50,endpoint=True,base=10.0,dtype=None,axis=0) 该函数返回一个对数刻度上的等比数列。数列范围为“[\(base^{start}\)\(base^{stop}\)]”,“base”默认为10。

1
2
3
4
5
6
7
# 在区间[10,100]内生成一个包含5个数据的等比数列
a = np.logspace(1, 2, num=5)

# 在区间[4,8]内生成一个包含4个数据的等比数列
b = np.logspace(2, 3, base=2, num=4)

print('a:', a, '\nb:', b)
a: [ 10.          17.7827941   31.6227766   56.23413252 100.        ] 
b: [4.         5.0396842  6.34960421 8.        ]

1.3 创建规模数组

1.3.1 np.zerosnp.zeros_like

np.zeros(shape, dtype=float, order='C') 该函数返回一个全为0的数组。数组形状由参数“shape”决定,“shape”可以是整数也可以是一个元组,当shape为整数时返回一个一维数组。

np.zeros_like(a, dtype=None, order='K', subok=True, shape=None) 该函数返回一个数据全为0,但与数组“a”具有相同形状和数据类型的新数组。

1
2
3
4
a = np.zeros(10)
b = np.zeros((2, 3))

print('a:\n', a, '\nb:\n', b)
a:
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 
b:
 [[0. 0. 0.]
 [0. 0. 0.]]
1
2
3
4
a = np.arange(1, 13).reshape(3, 4)
b = np.zeros_like(a)

print('a:\n', a, '\nb:\n', b)
a:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]] 
b:
 [[0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]]

1.3.2 np.onesnp.ones_like

np.ones(shape, dtype=None, order='C') 该函数返回一个全为1的数组。

np.ones_like(a, dtype=None, order='K', subok=True, shape=None) 该函数返回一个数据全为1,但与数组“a”具有相同形状和数据类型的新数组。

1
2
3
4
a = np.ones(5)
b = np.ones((3, 4))

print('a:\n', a, '\nb:\n', b)
a:
 [1. 1. 1. 1. 1.] 
b:
 [[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]]
1
2
3
4
a = np.arange(1, 13).reshape(3, 4)
b = np.ones_like(a)

print('a:\n', a, '\nb:\n', b)
a:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]] 
b:
 [[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

1.3.3 np.full()np.full_like()

np.full(shape, fill_value, dtype=None, order='C') 返回一个给定形状和数据类型的新数组,数组数据全为给定值“fill_value”。

np.full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None) 返回一个数据全为值“fill_value”,但与数组“a”具有相同形状和数据类型的新数组。

1
2
3
4
a = np.full(5, 3.14)
b = np.full((2, 3), 3.14)

print('a:\n', a, '\nb:\n', b)
a:
 [3.14 3.14 3.14 3.14 3.14] 
b:
 [[3.14 3.14 3.14]
 [3.14 3.14 3.14]]
1
2
3
4
a = np.arange(1, 13).reshape(3, 4)
b = np.full_like(a, 3)

print('a:\n', a, '\nb:\n', b)
a:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]] 
b:
 [[3 3 3 3]
 [3 3 3 3]
 [3 3 3 3]]

注意: zeros_likeones_likefull_like 都只能产生与所给数组具有相同数据类型的数组。

1
2
3
4
a = np.arange(1, 13).reshape(3, 4)
b = np.arange(1, 7, 0.5).reshape(3, 4)

print('a_dtype:', a.dtype, '\nb_dtype:', b.dtype)
a_dtype: int32 
b_dtype: float64
1
2
3
4
c_a = np.zeros_like(a)
c_b = np.zeros_like(b)

print('c_a_dtype:', c_a.dtype, '\nc_b_dtype:', c_b.dtype)
c_a_dtype: int32 
c_b_dtype: float64
1
2
3
4
d_a = np.full_like(a, 3.14)
d_b = np.full_like(b, 3.14)

print('d_a_dtype:', d_a.dtype, '\nd_b_dtype:', d_b.dtype)
d_a_dtype: int32 
d_b_dtype: float64

1.3.4 np.eye()

np.eye(N, M=None, k=0, dtype=<class 'float'>, order='C') 返回一个N×M的二维数组,数组对角线值为1,其余为0。M默认等于N,k为对角线的索引,默认为0。

1
2
3
4
5
a = np.eye(3)
b = np.eye(3, 4)
c = np.eye(3, 4, k=1)

print('a:\n', a, '\nb:\n', b, '\nc:\n', c)
a:
 [[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]] 
b:
 [[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]] 
c:
 [[0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

1.3.5 np.random()

random 是NumPy的一个模块,内含诸多函数,较为常用的由rand、randn、randint、random、normal、seed 等函数。

  • np.random.rand(d0, d1, ..., dn) 返回一个指定维度、数据介于[0,1)的数组,参数d为维度。
1
2
3
4
# 生成一个一维随机数组 a

a = np.random.rand(5)
print('a:\n', a, '\na_nidm:', a.ndim, '\na_shape:', a.shape)
a:
 [0.60190474 0.79229068 0.08220012 0.85542785 0.2297879 ] 
a_nidm: 1 
a_shape: (5,)
1
2
3
4
# 生成一个二维随机数组 b,2行3列

b = np.random.rand(2, 3)
print('b:\n', b, '\nb_nidm:', b.ndim, '\nb_shape:', b.shape)
b:
 [[0.8527445  0.59884459 0.56320288]
 [0.85995761 0.50276433 0.23505394]] 
b_nidm: 2 
b_shape: (2, 3)
1
2
3
4
# 生成一个三维随机数组 c,2个3行4列

c = np.random.rand(2, 3, 4)
print('c:\n', c, '\nc_nidm:', c.ndim, '\nc_shape:', c.shape)
c:
 [[[0.37208962 0.03070275 0.78003387 0.22731879]
  [0.63874307 0.94845367 0.71938931 0.11407476]
  [0.80291404 0.96805784 0.43899818 0.16440592]]

 [[0.89889721 0.94304281 0.88829921 0.77083897]
  [0.68389236 0.13407766 0.21058904 0.88371983]
  [0.69483851 0.86725109 0.15152504 0.64838383]]] 
c_nidm: 3 
c_shape: (2, 3, 4)
  • np.random.randint(low, high=None, size=None, dtype=int) 返回一个随机整数数组,数据范围[low,high),如果“ high”为“无”(默认值),则结果来自[0,low)。参数“size”决定数组的维度。参数“low”和“high”既可以是整数,也可以是元组。
1
2
3
4
# 从[0,100)范围内生成一个一维的随机整数数组

a = np.random.randint(100, size=5)
print('a:\n', a)
a:
 [74  0  7 78 38]
1
2
3
4
# 从[10,500)范围内生成一个二维(2行4列)随机整数数组

b = np.random.randint(10, 500, size=(2, 4))
print('b:\n', b)
b:
 [[299  85 386 307]
 [ 69 220 499 249]]
1
2
3
4
# 分别从[1,3)、[1,5)、[1,10)区间各生成一个随机整数,组成一个一维数组

c = np.random.randint(1, [3, 5, 10])
print('c:\n', c)
c:
 [1 1 5]
1
2
3
4
# 分别从[1,10)、[5,10)、[7,10)区间各生成一个随机整数,组成一个一维数组

d = np.random.randint([1, 5, 7], 10)
print('d:\n', d)
d:
 [7 8 9]
1
2
3
4
# 生成一个二维随机整数数组

e = np.random.randint([1, 3, 5, 7], [[10], [20]])
print('e:\n', e)
e:
 [[ 3  4  7  8]
 [ 1 19  9 14]]
  • np.random.random(size=None) 返回一个随机浮点数数组,数据范围为[0,1)
1
2
3
4
# 生成一个二维随机浮点数数组

a = np.random.random((3, 3))
print('a:\n', a)
a:
 [[0.59745994 0.29976794 0.44992556]
 [0.63682168 0.80479305 0.67311453]
 [0.77075207 0.61300261 0.41127895]]
  • np.random.normal(loc=0.0, scale=1.0, size=None) 从正态(高斯)分布中抽取随机样本。参数“loc”表示概率分布的均值,对应着整个分布的中心cente;“scale"表示概率分布的标准差,对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高;“loc”和“scale"都必须是浮点数或浮点数组成的元组
1
2
3
4
# 创建均值为0、标准差为1的二维(2×3)正态分布随机数组

a = np.random.normal(0.0, 1.0, (2, 3))
print('a:\n', a)
a:
 [[ 1.25935466  0.59439736 -0.16857579]
 [ 1.08024485  0.77929309  0.96025698]]
  • np.random.seed(self, seed=None) 生成一个随机数种子,用于指定随机数生成时所用算法开始的整数值。如果使用相同的seed( )值,则每次生成的随即数都相同;如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。设置的seed()值仅一次有效。
1
2
3
4
5
6
7
# 使用相同的seed,生成的随机数相同

num = 0
while(num < 5):
np.random.seed(3)
print(np.random.random())
num += 1
0.5507979025745755
0.5507979025745755
0.5507979025745755
0.5507979025745755
0.5507979025745755
1
2
3
4
5
6
7
# 虽然使用相同的seed,但seed只能生效一次,故生成的随机数不同

num = 0
np.random.seed(3)
while(num < 5):
print(np.random.random())
num += 1
0.5507979025745755
0.7081478226181048
0.2909047389129443
0.510827605197663
0.8929469543476547

2 数组的索引与切片

索引和切片的语法相同,在一维数组中表示为x[start:stop:step],在多维数组中,用逗号分隔的方式获取不同维度的元素x[start:stop:step, start:stop:step, ...]。三个参数的默认值分别为start=0,stop=维度的大小和step=1。

1
2
a = np.random.randint(10, size=10)
print('a:\n', a)
a:
 [9 9 5 7 6 0 4 7 8 1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 获取第一个元素
print(a[0])

# 获取最后一个元素
print(a[-1])

# 获取前五个元素
print(a[:5])

# 获取最后三个元素
print(a[7:])

# 获取中间四个元素
print(a[3:7])

# 间隔一个元素获取
print(a[::2])

# 所有元素逆序
print(a[::-1])

# 从索引5开始间隔一个元素逆序
print(a[5::-2])
9
1
[9 9 5 7 6]
[7 8 1]
[7 6 0 4]
[9 5 6 4 8]
[1 8 7 4 0 6 7 5 9 9]
[0 7 9]
1
2
b = np.random.randint(10, size=(3, 4))
print('b:\n', b)
b:
 [[6 2 2 1]
 [3 5 8 1]
 [8 7 8 1]]
1
2
3
4
5
6
print(b[0, 0])
print(b[2, 3])
print(b[1, -1])
print(b[:2, :3])
print(b[::1, ::2])
print(b[::-1, ::-1])
6
1
1
[[6 2 2]
 [3 5 8]]
[[6 2]
 [3 8]
 [8 8]]
[[1 8 7 8]
 [1 8 5 3]
 [1 2 2 6]]
1
2
c = np.random.randint(100, size=(2, 3, 4))
print('c:\n', c)
c:
 [[[79 48 37 20]
  [94 49 21 78]
  [28 54  0 64]]

 [[18 63 37 56]
  [56 71 37 46]
  [33  1 85 74]]]
1
2
3
4
print(c[0, 1, 2])
print(c[1, 0, -1])
print(c[0, :2, :3])
print(c[::-1, ::-1, ::-1])
21
56
[[79 48 37]
 [94 49 21]]
[[[74 85  1 33]
  [46 37 71 56]
  [56 37 63 18]]

 [[64  0 54 28]
  [78 21 49 94]
  [20 37 48 79]]]

索引和切片出来的部分是数组的视图,并非副本,这意味着修改这部分数值时,原数组数据也会改变。

1
2
3
4
5
6
a = np.random.randint(10, size=10)
print('a_0:', a[0])

a[0] = 100

print('a_0:', a[0])
a_0: 4
a_0: 100
1
2
3
4
5
6
7
8
9
10
b = np.random.randint(10, size=(3, 4))
print('b:\n', b)

b_sub = b[:2, :3]
print('\nb_sub:\n', b_sub)

b_sub[0, 0] = 100

print('\nb_sub:\n', b_sub)
print('\nb:\n', b)
b:
 [[5 0 1 4]
 [1 2 2 4]
 [8 0 6 0]]

b_sub:
 [[5 0 1]
 [1 2 2]]

b_sub:
 [[100   0   1]
 [  1   2   2]]

b:
 [[100   0   1   4]
 [  1   2   2   4]
 [  8   0   6   0]]

如果想要创建副本,可以使用copy()方法实现。创建副本后再修改子数组,原始数组就不会再随之更改了。

1
2
3
4
5
6
7
8
9
10
11
b = np.random.randint(10, size=(3, 4))
print('b:\n', b)

b_sub_copy = b[:2, :3].copy()
print('\nb_sub_copy:\n', b_sub_copy)

b_sub_copy[0, 0] = 99

print('\nb_sub_copy:\n', b_sub_copy)

print('\nb:\n', b)
b:
 [[4 1 5 1]
 [8 8 7 0]
 [0 9 1 7]]

b_sub_copy:
 [[4 1 5]
 [8 8 7]]

b_sub_copy:
 [[99  1  5]
 [ 8  8  7]]

b:
 [[4 1 5 1]
 [8 8 7 0]
 [0 9 1 7]]

在对数组值进行修改时需要注意,NumPy数组是固定类型的。这意味着当你试图将一个浮点数插入一个整型数组时,浮点值会被截短成整型,并且这种截短是自动完成的,不会提示或警告。

1
2
b_sub_copy[0, 0] = 3.14
print('b_sub_copy:\n', b_sub_copy)
b_sub_copy:
 [[3 1 5]
 [8 8 7]]

3 数组的变形

3.1 一维变二维

数组变形最为常用的方法是通过 reshape() 函数来实现,该函数在上一小节“创建数组”中已经介绍过。此处讲解另一种变形模式是将一个一维数组转变为二维的行或列的矩阵。此变形既可以通过 reshape 来实现,也可以通过 newaxis 关键字实现对数组的变形。

1
2
a = np.array([1, 2, 3])
print('a:\n', a, '\na_nidm:', a.ndim, '\na_shape:', a.shape)
a:
 [1 2 3] 
a_nidm: 1 
a_shape: (3,)
1
2
b = a.reshape((1, 3))
print('b:\n', b, '\nb_nidm:', b.ndim, '\nb_shape:', b.shape)
b:
 [[1 2 3]] 
b_nidm: 2 
b_shape: (1, 3)
1
2
c = a[np.newaxis, :]
print('c:\n', c, '\nc_nidm:', c.ndim, '\nc_shape:', c.shape)
c:
 [[1 2 3]] 
c_nidm: 2 
c_shape: (1, 3)

在上面的例子中,数组a是一维的,经过 reshape 和 newaxis 后变为二维数组,原数组a成为新数组的一行。从上面的例子可以看出,np.newaxis 的作用就是在其所在位置增加一个维度。也可以使用 reshape 和 newaxis 让原数组a成为新数组的一列:

1
2
d = a.reshape((3, 1))
print('d:\n', d, '\nd_nidm:', d.ndim, '\nd_shape:', d.shape)
d:
 [[1]
 [2]
 [3]] 
d_nidm: 2 
d_shape: (3, 1)
1
2
e = a[:, np.newaxis]
print('e:\n', e, '\ne_nidm:', e.ndim, '\ne_shape:', e.shape)
e:
 [[1]
 [2]
 [3]] 
e_nidm: 2 
e_shape: (3, 1)

3.2 数组的转置

另一种变形是数组的转置,NumPy提供了三种转置方法T、transpose和swapaxes。如果只对一、二维数组转置,可使用T方法,相对较为简单,只需在需要转置的数组后加.T 即可。高维数组的转置则需要使用transpose和swapaxes。transpose语法为:np.transpose(a, axes=None) 。swapaxes语法为:np.swapaxes(a, axis1, axis2) ,axis1 和 axis2 分别表示需要转换的两个轴。三维以上数组的转置暂时不深入学习。

1
2
a = np.arange(1, 13).reshape(3, 4)
print('a:\n', a)
a:
 [[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
1
2
3
4
5
6
7
8
b = a.T
print('b:\n', b)

c = np.transpose(a)
print('c:\n', c)

d = np.swapaxes(a, 0, 1)
print('d:\n', d)
b:
 [[ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]
 [ 4  8 12]]
c:
 [[ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]
 [ 4  8 12]]
d:
 [[ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]
 [ 4  8 12]]

4 数组的拼接

数组的拼接主要由np.concatenatenp.column_stacknp.vstacknp.hstack 来实现。

  • np.concatenate

完整函数为 concatenate((a1, a2, ...), axis=0, out=None) 。a1, a2, ... 是序列,各个序列应具有相同的大小,或经过axis参数后具有相同的大小。axis默认为0,表示沿第一个轴拼接,为1时表示沿第二个轴拼接。

1
2
3
4
5
6
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])

d = np.concatenate((a, b, c))
print('d:\n', d)
d:
 [1 2 3 4 5 6 7 8 9]
1
2
3
4
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print('a:\n', a)
print('b:\n', b)
a:
 [[1 2]
 [3 4]]
b:
 [[5 6]]
1
2
3
4
5
c = np.concatenate((a, b))
print('c:\n', c)

d = np.concatenate((a, b.T), axis=1)
print('d:\n', d)
c:
 [[1 2]
 [3 4]
 [5 6]]
d:
 [[1 2 5]
 [3 4 6]]
  • np.column_stack

np.column_stack(tup) 可以把一维数组变为二维数组的列。

1
2
3
4
5
6
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])

d = np.column_stack((a, b, c))
print('d:\n', d)
d:
 [[1 4 7]
 [2 5 8]
 [3 6 9]]
  • np.vstacknp.hstack

如果是沿着固定维度处理数组时,使用 np.vstack(垂直栈)和 np.hstack(水平栈)函数会更简洁。二者参数相同,完整函数为np.vstack(tup)np.hstack(tup) 。其中,tup 表示元组,也就是说把待处理的数组放进一个元组中作为整体。

1
2
3
4
5
6
7
8
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])

e = np.vstack((a, b))
print('e:\n', e)

f = np.hstack((a, b.T))
print('\nf:\n', f)
e:
 [[1 2]
 [3 4]
 [5 6]]

f:
 [[1 2 5]
 [3 4 6]]

5 数组的分割

与拼接相反的过程是分割,分割可以通过np.splitnp.vsplitnp.hsplit 来实现。分割数组时需要向函数传递一个索引列表作为参数,索引列表记录的是分割点位置。

  • np.split

完整函数为:np.split(ary, indices_or_sections, axis=0)

1
2
3
4
5
6
7
a = [1, 2, 3, 99, 99, 3, 2, 1]
print('a:\n', a)

b, c, d = np.split(a, [3, 5])
print('b:\n', b)
print('c:\n', c)
print('d:\n', d)
a:
 [1, 2, 3, 99, 99, 3, 2, 1]
b:
 [1 2 3]
c:
 [99 99]
d:
 [3 2 1]
1
2
3
4
5
6
7
a = np.arange(12).reshape(3, 4)
print('a:\n', a)

b, c, d = np.split(a, [1, 2])
print('b:\n', b)
print('c:\n', c)
print('d:\n', d)
a:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
b:
 [[0 1 2 3]]
c:
 [[4 5 6 7]]
d:
 [[ 8  9 10 11]]
1
2
3
b, c = np.split(a, [2], axis=1)
print('b:\n', b)
print('c:\n', c)
b:
 [[0 1]
 [4 5]
 [8 9]]
c:
 [[ 2  3]
 [ 6  7]
 [10 11]]
  • np.vsplitnp.hsplit

如果沿固定维度分割,可使用 np.vsplit(ary, indices_or_sections)np.hsplit(ary, indices_or_sections)

1
2
3
4
b, c, d = np.vsplit(a, [1, 2])
print('b:\n', b)
print('c:\n', c)
print('d:\n', d)
b:
 [[0 1 2 3]]
c:
 [[4 5 6 7]]
d:
 [[ 8  9 10 11]]
1
2
3
b, c = np.hsplit(a, [2])
print('b:\n', b)
print('c:\n', c)
b:
 [[0 1]
 [4 5]
 [8 9]]
c:
 [[ 2  3]
 [ 6  7]
 [10 11]]

小结

以上简单学习了NumPy数组的创建和操作,但这些大多是基于一维和二维数组的操作,是基础中的基础,需要不断练习强化。待熟练掌握后还需要进一步学习更多函数,如各种花式索引和切片,应用于三维数组的拼接和分割等等。

本章节内容基于以下资料学习整理而得:

  1. Python数据科学手册

  2. 3小时教你入门Numpy

  3. Numpy & Pandas(莫烦Python数据处理教程)

  4. Numpy基础入门