跳转到内容

User:Xyy23330121/Python/科学计算/数组

来自维基学院


数组是 numpy 中,表示矩阵或向量的工具。本章节的代码均以下面代码开头。

import numpy as np

本章将讲述数组作为容器对象的一些基本操作。

创建数组

[编辑 | 编辑源代码]

最基本的创建数组的方法,是使用 np.array 从列表创建数组。

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

类似的,也可以使用 np.ndarray.tolist() 方法从数组创建列表。

数组的形状

[编辑 | 编辑源代码]

数组是具有形状的,我们可以使用 shape,ndimsize属性来确定数组的形状。

#shape 代表数组的维数,以及每个维度的分量个数
print(a.shape)  #输出:(6, )
print(b.shape)  #输出:(3, 2)
print(c.shape)  #输出:(3, 2, 2)
#ndim 代表数组的维数
print(a.ndim)   #输出:1
print(b.ndim)   #输出:2
print(c.ndim)   #输出:3
#size 代表数组的总数据量
print(a.size)   #输出:6
print(b.size)   #输出:6
print(c.size)   #输出:12

数组与索引

[编辑 | 编辑源代码]

一维数组

[编辑 | 编辑源代码]

一维数组和列表使用相似的方法进行索引。

print(a[0])   #输出:1
print(a[0:])  #输出:[1 2 3 4 5 6]
print(a[:1])  #输出:[1]
print(a[2:4]) #输出:[3 4]
print(a[::2]) #输出:[1 3 5]

但需要注意,列表经 slice 索引时,创建的是切片部分的副本——更改副本不改变原列表的内容。而数组所创建的则是对原数组的引用——更改引用会更改原数组的内容。比如:

d = [1,2,3,4,5,6] #创建列表
d2 = d[2:4]
d2[0] = 9
print(d,d2)    #输出:[1, 2, 3, 4, 5, 6] [9, 4]

更改子列表副本,并未更改原列表的内容。而:

a2 = a[2:4]
a2[0] = 9
print(a,a2)    #输出:[1 2 9 4 5 6] [9 4]

原数组的内容也被更改。这是为了计算时方便而定的。

多维数组

[编辑 | 编辑源代码]

多维数组的索引方式与多维列表相似,又有较大的不同。我们看以下示例:

print(b[0])     #输出:[1 2]
print(b[1,1])   #输出:4
print(b[1,:])   #输出:[3 4]
print(b[:,1])   #输出:[2 4 6]
print(c[1])     #输出:[[5 6]
                #       [7 8]]
print(c[1,1])   #输出:[7 8]
print(c[1,1,1]) #输出:9
print(c[1,:,1]) #输出:[6 8]

在进行索引时,与一维数组类似,如果索引得到的结果为 np.array 类型,则结果仅为原数组的引用,而非原数组的副本。

c1 = c[1,1]    #得到的对象类型:np.array
c1[1] = 9
print(c[1,1])  #输出:[7 9]
c2 = c[1,1,1]  #得到的对象类型:int
c2 = 8
print(c[1,1])  #输出:[7 9]

特殊索引方式

[编辑 | 编辑源代码]

数组支持输入一个由布尔值组成的数组作为其索引,比如:

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

#利用数组和整数的比较运算,创建由布尔值组成的数组。
#数组和数字,数组和数组的运算将在下一章讲解。数组内数据类型将在本页最下面讲解。
print(a<5)    #输出:[ True  True  True  True False False False False]

#用该数组进行索引。
print(a[a<5]) #输出:[1 2 3 4]
print(b[a<5]) #输出:[8 7 6 5]

此时,要求作为索引的布尔值数组,其size属性和被索引数组的size属性相等。

更多索引方式

[编辑 | 编辑源代码]

参见:

调整数组的形状

[编辑 | 编辑源代码]

np.ndarray.reshape(shape) 方法会返回数组变形后的引用。数组变形前后各元素顺序不变。

a = np.array([i for i in range(6)])
print(a)
#输出:[0 1 2 3 4 5]

b = a.reshape((2,3)) #变形

print(a)
#输出:[0 1 2 3 4 5]
#可见该方法并不改变原数组,而是返回了更改后的新的版本

print(b)
#输出:
#[[0 1 2]
# [3 4 5]]
#数字3依旧是数字2的下一个元素,元素顺序没有改变。

b[0,0] = 6
print(a)
#输出:[6 1 2 3 4 5]
#类似 数组与索引 章节的内容,变形后的数组并非副本,而是一个具有不同形状的引用。

更具体的用法,参见文档:

以及相关内容:

特别的,np.ndarray.flatten() 方法会返回变形为一维的一个引用。它等同于:

a.reshape((a.size,))

a.T 属性会返回原数组 a 的转置。以三维数组为例,转置会将原本索引为 [x, y, z] 的元素变更到索引为 [z, y, x] 的位置。我们测试以下的示例

a = np.array([i for i in range(30)])
a = a.reshape((2,3,5))

aT = a.T
result = True
for x in range(2):
    for y in range(3):
        for z in range(5):
            #对每个索引测试其元素
            result = (result and (a[x,y,z] == aT[z,y,x]))
print(result) #输出:True

aT[3,2,1] = 114
print(a[1,2,3]) #输出:114,可见转置生成的也是引用。

更多相关内容参见:

添加维度

[编辑 | 编辑源代码]

除了 reshape 方法可以增加维度之外,numpy 额外提供了一种通过索引增加维度的方式。

print(np.newaxis is None)  #输出:True

a = np.array([0, 1, 2])
b = a[:, np.newaxis]
print(b)
#输出:
#[[0]
# [1]
# [2]]
# 为使 a[x] == b[x, 0] 的引用。

参见:

延申阅读

[编辑 | 编辑源代码]

以下文档包含了更多更改数组形状的方法:


特殊数组的创建

[编辑 | 编辑源代码]

一些常用数组无需使用列表来创建,比如:

d = np.zeros(2)   #形状为(2, )的全零数组。
e = np.zeros(2,2) #形状为(2, 2)的全零数组。

f = np.ones(2)    #形状为(2, )的全一数组。
g = np.ones(2,2)  #形状为(2, 2)的全一数组。

除此之外,还有类似 slice 索引的:

h = np.arange(4)     #[0 1 2 3]
i = np.arange(2,4)   #[2 3]
j = np.arange(1,7,2) #[1 3 5]
k = np.arange(0, 1, 0.3) #[0 0.3 0.6 0.9]

以及用于线性采样的:

l = np.linspace(0, 10, num=5) #5个数字组成的等差数组,起始为0,终止为10
                              #[0 2.5 5 7.5 10]
                              #即:在0~10之间取样5个点。

以下文档提供了更多创建特殊数组的方法: