构建数组

日期2018-03-26(最后修改),2006-02-07(创建)

本节简要介绍数组对象,包括其声明和在 SciPy 中的使用。有关 Numpy 数组函数的全面示例列表,请参阅 Numpy 示例列表及文档

基础

标准 Python 语言中尚未定义数值数组。要将数组对象及其方法加载到命名空间中,必须导入 Numpy 包

In [2]
from numpy import *

可以使用 array 函数从通常的 Python 列表和元组创建数组。例如,

In [3]
a = array([1,2,3])

返回一个一维整数数组。数组实例附带有一组大量的方法和属性。例如,是数组的维度。在本例中,它将是 。

数组对象与 Python 的序列对象之间的一个主要区别是数学运算符的定义。两个列表的加法会将这些列表连接起来,而两个数组的加法会逐元素地添加数组。例如,

In [4]
b = array((10,11,12))
a + b
Out[4]
array([11, 13, 15])

减法、乘法和除法类似地定义。

初学者常犯的一个错误是数组的类型定义。除非另有说明,否则 array 构造函数将使用其参数的类型。由于 是从整数列表创建的,因此它被定义为一个整数数组,更准确地说,是

In [5]
a.dtype
Out[5]
dtype('int64')

因此,像除法这样的数学运算在 Python 中将按预期进行,即返回整数答案。

In [6]
a/3
Out[6]
array([0.33333333, 0.66666667, 1.        ])

为了获得预期的答案,一种解决方案是通过除以一个实数来强制将整数转换为实数。更谨慎的方法是在初始化时定义类型。

In [7]
a = array([1,2,3], dtype=float)

另一种转换方法是使用 NumPy 的内置转换函数 astypecast。这些函数允许您更改正在处理的数据类型。

In [8]
a = array([1,2,3], dtype=int)
b = a.astype('float')

使用方括号表示法访问数组元素,其中 是从 0 开始的整数索引。可以使用 start:stop:step 格式的通用索引访问子数组。a[start:stop:step] 将返回对数组 a 的子数组的引用,该子数组从索引 start 处的元素开始(包括),一直到索引 stop 处的元素(不包括),步长为 step。例如:

In [9]
data = array([0.5, 1.2, 2.2, 3.4, 3.5, 3.4, 3.4, 3.4], float)
t = arange(len(data), dtype='float') * 2*pi/(len(data)-1)
t[:]              # get all t-values
Out[9]
array([0.        , 0.8975979 , 1.7951958 , 2.6927937 , 3.5903916 ,
       4.48798951, 5.38558741, 6.28318531])
In [10]
t[2:4]            # get sub-array with the elements at the indexes 2,3
Out[10]
array([1.7951958, 2.6927937])
In [11]
t[slice(2,4)]     # the same using slice
Out[11]
array([1.7951958, 2.6927937])
In [12]
t[0:6:2]          # every even-indexed value up to but excluding 6
Out[12]
array([0.       , 1.7951958, 3.5903916])

此外,还可以使用布尔数组访问数组元素。布尔数组的元素索引设置为 True,表示要访问的元素。

In [13]
i = array(len(t)*[False], bool)        # create an bool-array for indexing
i[2] = True; i[4] = True; i[6] = True  # we want elements with indexes 2,4 and 6
t[i]
Out[13]
array([1.7951958 , 3.5903916 , 5.38558741])

我们可以使用这种语法来构建更复杂的结构。考虑之前定义的 data[:]t[:] 数组。假设我们想要获取四个 (t[i]/data[i]) 对,其中四个 t[i] 值最接近点 p=1.8。我们可以按照以下步骤进行:

In [14]
p=1.8                            # set our point
abs(t-p)                         # how much do the t[:]-values differ from p?
Out[14]
array([1.8       , 0.9024021 , 0.0048042 , 0.8927937 , 1.7903916 ,
       2.68798951, 3.58558741, 4.48318531])
In [15]
dt_m = sort(abs(t-p))[3]         # how large is the 4-th largest absolute distance between the
                                 # t[:]-values and p
In [16]
abs(t-p) <= dt_m                 # where are the four elements of t[:]closest to p ?
Out[16]
array([False,  True,  True,  True,  True, False, False, False])
In [17]
y_p = data[abs(t-p) <= dt_m]     # construct the sub-arrays; (1) get the 4 t[:]-values
t_p = t[abs(t-p) <= dt_m]        # (2) get the data t[:]-values corresponding to the 4 t[:] values
y_p
Out[17]
array([1.2, 2.2, 3.4, 3.5])
In [18]
t_p
Out[18]
array([0.8975979, 1.7951958, 2.6927937, 3.5903916])

需要注意的是,切片返回对数据的引用。因此,返回的子数组中的更改会导致原始数组中的更改,反之亦然。如果只想复制值,可以使用矩阵对象的 copy() 方法。例如:

In [19]
# first lets define a 2-d matrix
A = array([[0,   1,  2,  3],   # initialize 2-d array
           [4,   5,  6,  7],
           [8,   9, 10, 11],
           [12, 13, 14, 15]])
A
Out[19]
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
In [20]
b=A[1:3,0:2]                    # let's get a sub-matrix containing the cross-section of
                                # rows 1,2 and columns 0,1
                                # !attention! this assigns to b a reference to the
                                # sub-matrix of A
b
Out[20]
array([[4, 5],
       [8, 9]])
In [21]
c=A[1:3,0:2].copy()             # copy the entries
c
Out[21]
array([[4, 5],
       [8, 9]])
In [22]
A[1:3,0:2] = 42                 # we can also assign by slicing (this also changes shallow copies)
b                               # b also affected (only a reference to sub matrix)
Out[22]
array([[42, 42],
       [42, 42]])
In [23]
c                               # still the same (deep copy)
Out[23]
array([[4, 5],
       [8, 9]])

矩阵点积

以下示例创建两个矩阵:ab,并计算点积 axb(换句话说,标准矩阵乘积)。

In [24]
a = array([[1,2], [2,3]])
b = array([[7,1], [0,1]])
dot(a, b)
Out[24]
array([[ 7,  3],
       [14,  5]])

从 Python 3.5 开始,可以使用 @ 运算符进行矩阵乘法。

In [25]
a @ b
Out[25]
array([[ 7,  3],
       [14,  5]])

自动数组创建

SciPy(通过 Numpy)提供了多种方法来自动创建数组。例如,要创建等间距数字的向量,可以使用 linspace 函数。这在计算函数在某个域上的结果时很有用。例如,要计算函数在一个周期上的值,我们可以定义一个从 0 到 2π(π)的向量,并计算该向量中所有值的函数值。

在 [26] 中
x = linspace(0, 2*pi, 100)
y = sin(x)

可以使用类及其一些对象创建方法在 N 维网格上执行相同的操作。例如,

在 [27] 中
x, y = mgrid[0:10:.1, 0:10:.2]

返回两个矩阵 x 和 y,其元素分别以 0.1 和 0.2 的增量从 0 到 10(不包括 10)。这些矩阵可用于计算由这些网格定义的点 (x_i, y_i) 上的函数值。

在 [28] 中
z = (x+y)**2

ogrid 对象具有完全相同的行为,但它不将 N 维矩阵存储到内存中,而是只存储定义它的 1 维向量。对于大型矩阵,这可以节省大量的内存空间。

其他用于创建矩阵的有用函数是 和 ,它们初始化全为零和一的数组。请注意,这些数组默认情况下将是浮点数组。这可能会导致不了解的人产生奇怪的行为。例如,让我们初始化一个全为零的矩阵,然后逐元素地放置值。

在 [29] 中
mz = zeros((2, 2), dtype=int)
mz[0, 0] = .5**2
mz[1, 1] = 1.6**2

在这个例子中,我们试图将浮点数存储到一个整数数组中。因此,这些数字将被重新转换为整数,所以如果我们打印矩阵,我们会得到

在 [30] 中
mz
Out[30]
array([[0, 0],
       [0, 2]])

要创建实数数组,只需在调用函数时明确指定类型即可。

在 [31] 中
mz = zeros((2, 2), dtype=float)

重复数组段

ndarray.repeat() 方法返回一个新的数组,其维度从旧数组中重复。

在 [32] 中
a = array([[0, 1],
...        [2, 3]])
a.repeat(2, axis=0) # repeats each row twice in succession
Out[32]
array([[0, 1],
       [0, 1],
       [2, 3],
       [2, 3]])
在 [33] 中
a.repeat(3, axis=1) # repeats each column 3 times in succession
Out[33]
array([[0, 0, 0, 1, 1, 1],
       [2, 2, 2, 3, 3, 3]])
在 [34] 中
a.repeat(2, axis=None) # flattens (ravels), then repeats each element twice
Out[34]
array([0, 0, 1, 1, 2, 2, 3, 3])

这些可以组合起来做一些有用的事情,比如放大存储在 2D 数组中的图像数据。

在 [35] 中
def enlarge(a, x=2, y=None):
    """Enlarges 2D image array a using simple pixel repetition in both dimensions.
    Enlarges by factor x horizontally and factor y vertically.
    If y is left as None, uses factor x for both dimensions."""
    a = asarray(a)
    assert a.ndim == 2
    if y == None:
        y = x
    for factor in (x, y):
        assert factor.__class__ == int
        assert factor > 0
    return a.repeat(y, axis=0).repeat(x, axis=1)

enlarge(a, x=2, y=2)
Out[35]
array([[0, 0, 1, 1],
       [0, 0, 1, 1],
       [2, 2, 3, 3],
       [2, 2, 3, 3]])

章节作者:DavidHuard,Unknown[26],Unknown[27],GaelVaroquaux,Unknown[28],BillBaxter,NilsWagner,MartinSpacek,Unknown[29],Unknown[5],Unknown[30],Unknown[31],Unknown[32],arjen,Joseph C. Slater