NumPy 1.26 中文官方指南(一)(1)https://developer.aliyun.com/article/1510631
高级索引和索引技巧
NumPy 提供比普通 Python 序列更多的索引工具。除了之前我们所见到的按整数和切片进行索引之外,数组还可以通过整数数组和布尔数组进行索引。
使用索引数组进行索引
>>> a = np.arange(12)**2 # the first 12 square numbers >>> i = np.array([1, 1, 3, 8, 5]) # an array of indices >>> a[i] # the elements of `a` at the positions `i` array([ 1, 1, 9, 64, 25]) >>> >>> j = np.array([[3, 4], [9, 7]]) # a bidimensional array of indices >>> a[j] # the same shape as `j` array([[ 9, 16], [81, 49]])
当索引数组a
是多维的时,单个索引数组会引用a
的第一个维度。以下示例通过使用调色板,将标签图像转换为彩色图像展示了这种行为。
>>> palette = np.array([[0, 0, 0], # black ... [255, 0, 0], # red ... [0, 255, 0], # green ... [0, 0, 255], # blue ... [255, 255, 255]]) # white >>> image = np.array([[0, 1, 2, 0], # each value corresponds to a color in the palette ... [0, 3, 4, 0]]) >>> palette[image] # the (2, 4, 3) color image array([[[ 0, 0, 0], [255, 0, 0], [ 0, 255, 0], [ 0, 0, 0]], [[ 0, 0, 0], [ 0, 0, 255], [255, 255, 255], [ 0, 0, 0]]])
我们还可以为多个维度提供索引。每个维度的索引数组必须具有相同的形状。
>>> a = np.arange(12).reshape(3, 4) >>> a array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> i = np.array([[0, 1], # indices for the first dim of `a` ... [1, 2]]) >>> j = np.array([[2, 1], # indices for the second dim ... [3, 3]]) >>> >>> a[i, j] # i and j must have equal shape array([[ 2, 5], [ 7, 11]]) >>> >>> a[i, 2] array([[ 2, 6], [ 6, 10]]) >>> >>> a[:, j] array([[[ 2, 1], [ 3, 3]], [[ 6, 5], [ 7, 7]], [[10, 9], [11, 11]]])
在 Python 中,arr[i, j]
与arr[(i, j)]
完全相同 - 因此我们可以将i
和j
放入一个tuple
,然后使用该索引。
>>> l = (i, j) >>> # equivalent to a[i, j] >>> a[l] array([[ 2, 5], [ 7, 11]])
然而,我们不能将i
和j
放入一个数组中来做到这一点,因为这个数组会被解释为索引a
的第一个维度。
>>> s = np.array([i, j]) >>> # not what we want >>> a[s] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: index 3 is out of bounds for axis 0 with size 3 >>> # same as `a[i, j]` >>> a[tuple(s)] array([[ 2, 5], [ 7, 11]])
使用数组进行索引的另一个常见用途是搜索时序系列的最大值:
>>> time = np.linspace(20, 145, 5) # time scale >>> data = np.sin(np.arange(20)).reshape(5, 4) # 4 time-dependent series >>> time array([ 20\. , 51.25, 82.5 , 113.75, 145\. ]) >>> data array([[ 0\. , 0.84147098, 0.90929743, 0.14112001], [-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ], [ 0.98935825, 0.41211849, -0.54402111, -0.99999021], [-0.53657292, 0.42016704, 0.99060736, 0.65028784], [-0.28790332, -0.96139749, -0.75098725, 0.14987721]]) >>> # index of the maxima for each series >>> ind = data.argmax(axis=0) >>> ind array([2, 0, 3, 1]) >>> # times corresponding to the maxima >>> time_max = time[ind] >>> >>> data_max = data[ind, range(data.shape[1])] # => data[ind[0], 0], data[ind[1], 1]... >>> time_max array([ 82.5 , 20\. , 113.75, 51.25]) >>> data_max array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ]) >>> np.all(data_max == data.max(axis=0)) True
你还可以使用数组作为目标进行编制索引:
>>> a = np.arange(5) >>> a array([0, 1, 2, 3, 4]) >>> a[[1, 3, 4]] = 0 >>> a array([0, 0, 2, 0, 0])
然而,当索引列表包含重复项时,赋值会多次进行,留下最后一个值:
>>> a = np.arange(5) >>> a[[0, 0, 2]] = [1, 2, 3] >>> a array([2, 1, 3, 3, 4])
虽然这是足够合理的,但要注意如果你想使用 Python 的+=
构造,因为它可能不会如你所期望地运行:
>>> a = np.arange(5) >>> a[[0, 0, 2]] += 1 >>> a array([1, 1, 3, 3, 4])
尽管索引列表中 0 出现了两次,但第 0 个元素只增加了一次。这是因为 Python 要求a += 1
等价于a = a + 1
。
使用布尔数组进行索引
当我们使用(整数)索引数组对数组进行索引时,我们提供要选择的索引列表。使用布尔索引时,方法不同;我们明确选择数组中的哪些项和哪些项不要。
对于布尔索引,最自然的想法之一是使用与原始数组相同形状的布尔数组:
>>> a = np.arange(12).reshape(3, 4) >>> b = a > 4 >>> b # `b` is a boolean with `a`'s shape array([[False, False, False, False], [False, True, True, True], [ True, True, True, True]]) >>> a[b] # 1d array with the selected elements array([ 5, 6, 7, 8, 9, 10, 11])
这个特性在赋值中非常有用:
>>> a[b] = 0 # All elements of `a` higher than 4 become 0 >>> a array([[0, 1, 2, 3], [4, 0, 0, 0], [0, 0, 0, 0]])
你可以查看下面的例子,看如何使用布尔索引生成Mandelbrot 集合的图像:
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> def mandelbrot(h, w, maxit=20, r=2): ... """Returns an image of the Mandelbrot fractal of size (h,w).""" ... x = np.linspace(-2.5, 1.5, 4*h+1) ... y = np.linspace(-1.5, 1.5, 3*w+1) ... A, B = np.meshgrid(x, y) ... C = A + B*1j ... z = np.zeros_like(C) ... divtime = maxit + np.zeros(z.shape, dtype=int) ... ... for i in range(maxit): ... z = z**2 + C ... diverge = abs(z) > r # who is diverging ... div_now = diverge & (divtime == maxit) # who is diverging now ... divtime[div_now] = i # note when ... z[diverge] = r # avoid diverging too much ... ... return divtime >>> plt.clf() >>> plt.imshow(mandelbrot(400, 400))
使用布尔值进行索引的第二种方式更类似于整数索引;对数组的每个维度,我们提供一个选择我们想要的切片的 1D 布尔数组:
>>> a = np.arange(12).reshape(3, 4) >>> b1 = np.array([False, True, True]) # first dim selection >>> b2 = np.array([True, False, True, False]) # second dim selection >>> >>> a[b1, :] # selecting rows array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[b1] # same thing array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> a[:, b2] # selecting columns array([[ 0, 2], [ 4, 6], [ 8, 10]]) >>> >>> a[b1, b2] # a weird thing to do array([ 4, 10])
注意 1D 布尔数组的长度必须与您要切片的维度(或轴)的长度相一致。在前面的例子中,b1
的长度为 3(a
中的 行 数),而b2
(长度为 4)适合于索引a
的第 2 轴(列)。
ix_()
函数
ix_
函数可用于组合不同的向量,以便为每个 n-uplet(n 元组)的结果。例如,如果想要计算从向量 a、b 和 c 中取出的所有三元组的 a+b*c:
>>> a = np.array([2, 3, 4, 5]) >>> b = np.array([8, 5, 4]) >>> c = np.array([5, 4, 6, 8, 3]) >>> ax, bx, cx = np.ix_(a, b, c) >>> ax array([[[2]], [[3]], [[4]], [[5]]]) >>> bx array([[[8], [5], [4]]]) >>> cx array([[[5, 4, 6, 8, 3]]]) >>> ax.shape, bx.shape, cx.shape ((4, 1, 1), (1, 3, 1), (1, 1, 5)) >>> result = ax + bx * cx >>> result array([[[42, 34, 50, 66, 26], [27, 22, 32, 42, 17], [22, 18, 26, 34, 14]], [[43, 35, 51, 67, 27], [28, 23, 33, 43, 18], [23, 19, 27, 35, 15]], [[44, 36, 52, 68, 28], [29, 24, 34, 44, 19], [24, 20, 28, 36, 16]], [[45, 37, 53, 69, 29], [30, 25, 35, 45, 20], [25, 21, 29, 37, 17]]]) >>> result[3, 2, 4] 17 >>> a[3] + b[2] * c[4] 17
你也可以如下实现 reduce:
>>> def ufunc_reduce(ufct, *vectors): ... vs = np.ix_(*vectors) ... r = ufct.identity ... for v in vs: ... r = ufct(r, v) ... return r
然后使用它:
>>> ufunc_reduce(np.add, a, b, c) array([[[15, 14, 16, 18, 13], [12, 11, 13, 15, 10], [11, 10, 12, 14, 9]], [[16, 15, 17, 19, 14], [13, 12, 14, 16, 11], [12, 11, 13, 15, 10]], [[17, 16, 18, 20, 15], [14, 13, 15, 17, 12], [13, 12, 14, 16, 11]], [[18, 17, 19, 21, 16], [15, 14, 16, 18, 13], [14, 13, 15, 17, 12]]])
与普通的 ufunc.reduce 相比,这个 reduce 版本的优势在于它利用广播规则来避免创建一个大小等于输出乘以向量数量的参数数组。
使用字符串进行索引
参见结构化数组。
技巧和提示
这里我们列出一些简短且有用的提示。
“自动”重塑
要改变数组的维度,你可以省略其中一个尺寸,这样它将自动推导出来:
>>> a = np.arange(30) >>> b = a.reshape((2, -1, 3)) # -1 means "whatever is needed" >>> b.shape (2, 5, 3) >>> b array([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]], [[15, 16, 17], [18, 19, 20], [21, 22, 23], [24, 25, 26], [27, 28, 29]]])
向量堆叠
我们如何从一系列等大小的行向量构造一个二维数组?在 MATLAB 中,这相当容易:如果 x
和 y
是长度相同的两个向量,你只需要 m=[x;y]
。在 NumPy 中,这可以通过函数 column_stack
、dstack
、hstack
和 vstack
来实现,具体取决于堆叠的维度。例如:
>>> x = np.arange(0, 10, 2) >>> y = np.arange(5) >>> m = np.vstack([x, y]) >>> m array([[0, 2, 4, 6, 8], [0, 1, 2, 3, 4]]) >>> xy = np.hstack([x, y]) >>> xy array([0, 2, 4, 6, 8, 0, 1, 2, 3, 4])
那些超过两个维度的函数背后的逻辑可能会有些奇怪。
也请参见
NumPy 适用于 MATLAB 用户
直方图
应用于数组的 NumPy histogram
函数返回一对向量:数组的直方图和一个箱边的向量。注意:matplotlib
也有一个构建直方图的函数(称为 hist
,类似于 Matlab),它与 NumPy 中的函数不同。主要区别在于 pylab.hist
会自动绘制直方图,而 numpy.histogram
只会生成数据。
>>> import numpy as np >>> rg = np.random.default_rng(1) >>> import matplotlib.pyplot as plt >>> # Build a vector of 10000 normal deviates with variance 0.5² and mean 2 >>> mu, sigma = 2, 0.5 >>> v = rg.normal(mu, sigma, 10000) >>> # Plot a normalized histogram with 50 bins >>> plt.hist(v, bins=50, density=True) # matplotlib version (plot) (array...) >>> # Compute the histogram with numpy and then plot it >>> (n, bins) = np.histogram(v, bins=50, density=True) # NumPy version (no plot) >>> plt.plot(.5 * (bins[1:] + bins[:-1]), n)
使用 Matplotlib >=3.4,你也可以使用 plt.stairs(n, bins)
。
进一步阅读
- Python 教程
- NumPy 参考手册
- SciPy 教程
- SciPy 讲义
- 一个matlab、R、IDL、NumPy/SciPy 字典
- SVD 教程
先决条件
你需要了解一些 Python。需要复习的话,请参见Python 教程。
要运行示例,除了 NumPy 外,你还需要安装 matplotlib
。
学习者档案
这是 NumPy 中数组的快速概述。它演示了如何表示和操作 n 维((n>=2)))数组。特别是,如果你不知道如何将常见函数应用于 n 维数组(不使用 for 循环),或者如果你想了解 n 维数组的轴和形状属性,这篇文章可能会有所帮助。
学习目标
阅读后,你应该能够:
- 了解 NumPy 中一维、二维和 n 维数组之间的区别;
- 了解如何将一些线性代数操作应用于 n 维数组,而不使用 for 循环;
- 了解 n 维数组的轴和形状属性。
基础知识
NumPy 的主要对象是同构的多维数组。它是一个元素表(通常是数字),所有元素的类型相同,由非负整数的元组索引。在 NumPy 中,维度称为 轴。
例如,三维空间中一点的坐标数组 [1, 2, 1]
具有一个轴。该轴中有 3 个元素,因此我们说它的长度为 3。在下面的示例中,数组有 2 个轴。第一个轴长度为 2,第二个轴长度为 3。
[[1., 0., 0.], [0., 1., 2.]]
NumPy 的数组类称为 ndarray
。它也以别名 array
而闻名。注意 numpy.array
不同于标准 Python 库中的类 array.array
,后者只处理一维数组并提供较少的功能。ndarray
对象的更重要的属性有:
ndarray.ndim
数组的轴数(维数)。
ndarray.shape
数组的维度。这是一个整数元组,指示每个维度中数组的大小。对于具有 n 行和 m 列的矩阵,shape
将是 (n,m)
。因此,shape
元组的长度是轴数 ndim
。
ndarray.size
数组的元素总数。这等于 shape
元素的乘积。
ndarray.dtype
描述数组中元素类型的对象。可以使用标准的 Python 类型创建或指定 dtype。此外,NumPy 还提供了自己的类型。numpy.int32、numpy.int16 和 numpy.float64 是一些示例。
ndarray.itemsize
数组中每个元素的字节大小。例如,类型为 float64
的元素数组的 itemsize
为 8(=64/8),而类型为 complex32
的元素数组的 itemsize
为 4(=32/8)。它相当于 ndarray.dtype.itemsize
。
ndarray.data
包含数组实际元素的缓冲区。通常,我们不需要使用此属性,因为我们将使用索引功能访问数组中的元素。
一个例子
>>> import numpy as np >>> a = np.arange(15).reshape(3, 5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) >>> a.shape (3, 5) >>> a.ndim 2 >>> a.dtype.name 'int64' >>> a.itemsize 8 >>> a.size 15 >>> type(a) <class 'numpy.ndarray'> >>> b = np.array([6, 7, 8]) >>> b array([6, 7, 8]) >>> type(b) <class 'numpy.ndarray'>
数组创建
有几种创建数组的方法。
例如,可以使用 array
函数从常规的 Python 列表或元组创建数组。结果数组的类型是从序列中元素的类型推断出来的。
>>> import numpy as np >>> a = np.array([2, 3, 4]) >>> a array([2, 3, 4]) >>> a.dtype dtype('int64') >>> b = np.array([1.2, 3.5, 5.1]) >>> b.dtype dtype('float64')
经常出现的错误是调用 array
时提供多个参数,而不是提供一个序列作为参数。
>>> a = np.array(1, 2, 3, 4) # WRONG Traceback (most recent call last): ... TypeError: array() takes from 1 to 2 positional arguments but 4 were given >>> a = np.array([1, 2, 3, 4]) # RIGHT
array
将序列序列转换为二维数组,序列序列序列转换为三维数组,依此类推。
>>> b = np.array([(1.5, 2, 3), (4, 5, 6)]) >>> b array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
数组的类型也可以在创建时明确指定:
>>> c = np.array([[1, 2], [3, 4]], dtype=complex) >>> c array([[1.+0.j, 2.+0.j], [3.+0.j, 4.+0.j]])
通常,数组的元素最初是未知的,但其大小已知。因此,NumPy 提供了几个函数来创建带有初始占位符内容的数组。这些函数最小化了增长数组的必要性,这是一项昂贵的操作。
函数 zeros
创建一个全为零的数组,函数 ones
创建一个全为一的数组,函数 empty
创建一个初始内容是随机的数组,取决于内存状态。默认情况下,创建的数组的 dtype 是 float64
,但可以通过关键字参数 dtype
指定。
>>> np.zeros((3, 4)) array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) >>> np.ones((2, 3, 4), dtype=np.int16) array([[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]], dtype=int16) >>> np.empty((2, 3)) array([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260], # may vary [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])
要创建数字序列,NumPy 提供了arange
函数,它类似于 Python 内置的range
,但返回一个数组。
>>> np.arange(10, 30, 5) array([10, 15, 20, 25]) >>> np.arange(0, 2, 0.3) # it accepts float arguments array([0\. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
当arange
与浮点参数一起使用时,通常无法预测获得的元素数量,这是由于有限的浮点精度。因此,通常最好使用函数linspace
,它接收我们想要的元素数量作为参数,而不是步长:
>>> from numpy import pi >>> np.linspace(0, 2, 9) # 9 numbers from 0 to 2 array([0\. , 0.25, 0.5 , 0.75, 1\. , 1.25, 1.5 , 1.75, 2\. ]) >>> x = np.linspace(0, 2 * pi, 100) # useful to evaluate function at lots of points >>> f = np.sin(x)
另请参阅
array
, zeros
, zeros_like
, ones
, ones_like
, empty
, empty_like
, arange
, linspace
, numpy.random.Generator.rand, numpy.random.Generator.randn, fromfunction
, fromfile
打印数组
当您打印一个数组时,NumPy 会以嵌套列表的方式显示,但布局如下:
- 最后一轴从左到右打印,
- 倒数第二个从上到下打印,
- 其余部分也会从上到下打印,每个切片之间由一个空行分隔。
一维数组然后按行打印,二维数组按矩阵打印,三维数组按矩阵列表打印。
>>> a = np.arange(6) # 1d array >>> print(a) [0 1 2 3 4 5] >>> >>> b = np.arange(12).reshape(4, 3) # 2d array >>> print(b) [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] >>> >>> c = np.arange(24).reshape(2, 3, 4) # 3d array >>> print(c) [[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]]
请看下文以获取有关reshape
的更多详细信息。
如果数组太大无法打印,NumPy 会自动跳过数组的中心部分,只打印角落部分:
>>> print(np.arange(10000)) [ 0 1 2 ... 9997 9998 9999] >>> >>> print(np.arange(10000).reshape(100, 100)) [[ 0 1 2 ... 97 98 99] [ 100 101 102 ... 197 198 199] [ 200 201 202 ... 297 298 299] ... [9700 9701 9702 ... 9797 9798 9799] [9800 9801 9802 ... 9897 9898 9899] [9900 9901 9902 ... 9997 9998 9999]]
要禁用此行为并强制 NumPy 打印整个数组,您可以使用set_printoptions
更改打印选项。
>>> np.set_printoptions(threshold=sys.maxsize) # sys module should be imported
基本运算
数组上的算术运算符以逐元素方式应用。将创建一个新数组并填充结果。
>>> a = np.array([20, 30, 40, 50]) >>> b = np.arange(4) >>> b array([0, 1, 2, 3]) >>> c = a - b >>> c array([20, 29, 38, 47]) >>> b**2 array([0, 1, 4, 9]) >>> 10 * np.sin(a) array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854]) >>> a < 35 array([ True, True, False, False])
与许多矩阵语言不同,在 NumPy 数组中,乘积运算符*
以元素方式操作。可以使用@
运算符(在 python >=3.5 中)或dot
函数或方法执行矩阵乘积:
>>> A = np.array([[1, 1], ... [0, 1]]) >>> B = np.array([[2, 0], ... [3, 4]]) >>> A * B # elementwise product array([[2, 0], [0, 4]]) >>> A @ B # matrix product array([[5, 4], [3, 4]]) >>> A.dot(B) # another matrix product array([[5, 4], [3, 4]])
一些操作,例如+=
和*=
,会就地修改现有数组,而不是创建新数组。
>>> rg = np.random.default_rng(1) # create instance of default random number generator >>> a = np.ones((2, 3), dtype=int) >>> b = rg.random((2, 3)) >>> a *= 3 >>> a array([[3, 3, 3], [3, 3, 3]]) >>> b += a >>> b array([[3.51182162, 3.9504637 , 3.14415961], [3.94864945, 3.31183145, 3.42332645]]) >>> a += b # b is not automatically converted to integer type Traceback (most recent call last): ... numpy.core._exceptions._UFuncOutputCastingError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
在操作不同类型的数组时,结果数组的类型对应于更一般或更精确的类型(这种行为称为向上转型)。
>>> a = np.ones(3, dtype=np.int32) >>> b = np.linspace(0, pi, 3) >>> b.dtype.name 'float64' >>> c = a + b >>> c array([1\. , 2.57079633, 4.14159265]) >>> c.dtype.name 'float64' >>> d = np.exp(c * 1j) >>> d array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j, -0.54030231-0.84147098j]) >>> d.dtype.name 'complex128'
许多一元操作,如计算数组中所有元素的总和,都实现为ndarray
类的方法。
>>> a = rg.random((2, 3)) >>> a array([[0.82770259, 0.40919914, 0.54959369], [0.02755911, 0.75351311, 0.53814331]]) >>> a.sum() 3.1057109529998157 >>> a.min() 0.027559113243068367 >>> a.max() 0.8277025938204418
默认情况下,这些操作将应用于数组,就好像它是一个数字列表,而不考虑其形状。然而,通过指定axis
参数,你可以沿着数组的指定轴应用操作:
>>> b = np.arange(12).reshape(3, 4) >>> b array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> b.sum(axis=0) # sum of each column array([12, 15, 18, 21]) >>> >>> b.min(axis=1) # min of each row array([0, 4, 8]) >>> >>> b.cumsum(axis=1) # cumulative sum along each row array([[ 0, 1, 3, 6], [ 4, 9, 15, 22], [ 8, 17, 27, 38]])
通用函数
NumPy 提供了熟悉的数学函数,如 sin、cos 和 exp。在 NumPy 中,这些被称为“通用函数”(ufunc
)。在 NumPy 中,这些函数对数组进行逐元素操作,产生一个数组作为输出。
>>> B = np.arange(3) >>> B array([0, 1, 2]) >>> np.exp(B) array([1\. , 2.71828183, 7.3890561 ]) >>> np.sqrt(B) array([0\. , 1\. , 1.41421356]) >>> C = np.array([2., -1., 4.]) >>> np.add(B, C) array([2., 0., 6.])
另见
all
, any
, apply_along_axis
, argmax
, argmin
, argsort
, average
, bincount
, ceil
, clip
, conj
, corrcoef
, cov
, cross
, cumprod
, cumsum
, diff
, dot
, floor
, inner
, invert
, lexsort
, max
, maximum
, mean
, median
, min
, minimum
, nonzero
, outer
, prod
, re
, round
, sort
, std
, sum
, trace
, transpose
, var
, vdot
, vectorize
, where
索引、切片和迭代
一维数组可以像列表和其他 Python 序列一样进行索引、切片和迭代。
>>> a = np.arange(10)**3 >>> a array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]) >>> a[2] 8 >>> a[2:5] array([ 8, 27, 64]) >>> # equivalent to a[0:6:2] = 1000; >>> # from start to position 6, exclusive, set every 2nd element to 1000 >>> a[:6:2] = 1000 >>> a array([1000, 1, 1000, 27, 1000, 125, 216, 343, 512, 729]) >>> a[::-1] # reversed a array([ 729, 512, 343, 216, 125, 1000, 27, 1000, 1, 1000]) >>> for i in a: ... print(i**(1 / 3.)) ... 9.999999999999998 # may vary 1.0 9.999999999999998 3.0 9.999999999999998 4.999999999999999 5.999999999999999 6.999999999999999 7.999999999999999 8.999999999999998
多维数组每个轴可以有一个索引。这些索引以逗号分隔的元组形式给出:
>>> def f(x, y): ... return 10 * x + y ... >>> b = np.fromfunction(f, (5, 4), dtype=int) >>> b array([[ 0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33], [40, 41, 42, 43]]) >>> b[2, 3] 23 >>> b[0:5, 1] # each row in the second column of b array([ 1, 11, 21, 31, 41]) >>> b[:, 1] # equivalent to the previous example array([ 1, 11, 21, 31, 41]) >>> b[1:3, :] # each column in the second and third row of b array([[10, 11, 12, 13], [20, 21, 22, 23]])
当提供的索引少于轴的数量时,缺少的索引被视为完整的切片:
>>> b[-1] # the last row. Equivalent to b[-1, :] array([40, 41, 42, 43])
在b[i]
方括号中的表达式被视为i
,后面跟着需要表示剩余轴的:
的实例数。NumPy 还允许您使用点...
来编写这个表达式,即b[i, ...]
。
点 (...
) 表示需要产生一个完整索引元组所需的冒号数量。例如,如果x
是一个具有 5 个轴的数组,则
x[1, 2, ...]
等同于x[1, 2, :, :, :]
,x[..., 3]
转换为x[:, :, :, :, 3]
,以及x[4, ..., 5, :]
转换为x[4, :, :, 5, :]
。
>>> c = np.array([[[ 0, 1, 2], # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]], ... [[100, 101, 102], ... [110, 112, 113]]]) >>> c.shape (2, 2, 3) >>> c[1, ...] # same as c[1, :, :] or c[1] array([[100, 101, 102], [110, 112, 113]]) >>> c[..., 2] # same as c[:, :, 2] array([[ 2, 13], [102, 113]])
对多维数组的迭代是针对第一个轴完成的:
>>> for row in b: ... print(row) ... [0 1 2 3] [10 11 12 13] [20 21 22 23] [30 31 32 33] [40 41 42 43]
然而,如果想对数组中的每个元素执行操作,可以使用flat
属性,它是数组所有元素的迭代器:
>>> for element in b.flat: ... print(element) ... 0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43
另请参见
ndarrays 的索引, 索引例程 (参考), newaxis
, ndenumerate
, indices
NumPy 1.26 中文官方指南(一)(3)https://developer.aliyun.com/article/1510634