你需要懂一点Python。如需复习,请参阅 Python tutorial .
要使用这些示例,您需要 matplotlib 安装在NumPy之外。
matplotlib
学习者简介
这是NumPy中代数和数组的快速概述。它演示了n维 ( )数组被表示并且可以被操纵。特别是,如果您不知道如何将公共函数应用于n维数组(不使用for循环),或者您想了解n维数组的轴和形状属性,本文可能会有所帮助。
学习目标
阅读后,你应该能够:
了解NumPy中一维、二维和n维数组的区别;
了解如何在不使用for循环的情况下对n维数组应用一些线性代数运算;
了解n维数组的形状属性。
NumPy的主要对象是同构多维数组。它是一个元素表(通常是数字),所有元素都是相同类型的,由一个非负整数元组索引。在NumPy中,维度被称为 axes .
例如,三维空间中的点坐标 [1, 2, 1] 有一个轴。这个轴有3个元素,所以我们说它有3个长度。在下面的示例中,数组有两个轴。第一轴的长度为2,第二轴的长度为3。
[1, 2, 1]
[[1., 0., 0.], [0., 1., 2.]]
调用numpy的数组类 ndarray . 别名也知道 array . 注意 numpy.array 与标准的python库类不同 array.array 它只处理一维数组并提供较少的功能。更重要的属性 ndarray 对象是:
ndarray
array
numpy.array
array.array
数组的轴(维度)数。
数组的维度。这是一个整数元组,指示数组在每个维度中的大小。对于矩阵 n 行和 m 柱, shape 将 (n,m) . 的长度 shape 因此tuple是轴的数目, ndim .
shape
(n,m)
ndim
数组的元素总数。这等于 shape .
描述数组中元素类型的对象。可以使用标准的python类型创建或指定dtype。此外,numpy还提供自己的类型。numpy.int32、numpy.int16和numpy.float64是一些示例。
数组中每个元素的字节大小。例如,类型的元素数组 float64 有 itemsize 8(=64/8),而类型之一 complex32 有 itemsize 4(=32/8)。它相当于 ndarray.dtype.itemsize .
float64
itemsize
complex32
ndarray.dtype.itemsize
包含数组的实际元素的缓冲区。通常,我们不需要使用这个属性,因为我们将使用索引工具访问数组中的元素。
>>> 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 功能。结果数组的类型是根据序列中元素的类型推导出来的。
>>> 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 创建一个满是1的数组,函数 empty 创建初始内容是随机的且取决于内存状态的数组。默认情况下,创建的数组的数据类型为 float64 ,但可以通过关键字参数指定 dtype .
zeros
ones
empty
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 ,但返回一个数组。
arange
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 作为参数接收所需元素的数量,而不是步骤:
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
zeros_like
ones_like
empty_like
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]]]
见 below 获取更多详细信息 reshape .
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 .
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数组中操作elementwise。矩阵产品可以使用 @ 运算符(在python中>=3.5)或 dot 函数或方法:
*
@
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 参数可以沿数组的指定轴应用操作:
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中,这些函数对数组进行元素操作,生成一个数组作为输出。
ufunc
>>> 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
all
any
apply_along_axis
argmax
argmin
argsort
average
bincount
ceil
clip
conj
corrcoef
cov
cross
cumprod
cumsum
diff
floor
inner
invert
lexsort
max
maximum
mean
median
min
minimum
nonzero
outer
prod
re
round
sort
std
sum
trace
transpose
var
vdot
vectorize
where
One-dimensional 数组可以被索引、切片和迭代,就像 lists 以及其他的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 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] is treated as an i followed by as many instances of : as needed to represent the remaining axes. NumPy also allows you to write this using dots as `` 乙 [i、 是的。。。] ''.
b[i]
i
这个 dots (... )根据需要表示尽可能多的冒号,以生成完整的索引元组。例如,如果 x 是一个有5个轴的数组,然后
...
x
x[1, 2, ...] 等于 x[1, 2, :, :, :] ,
x[1, 2, ...]
x[1, 2, :, :, :]
x[..., 3] 到 x[:, :, :, :, 3] 和
x[..., 3]
x[:, :, :, :, 3]
x[4, ..., 5, :] 到 x[4, :, :, 5, :] .
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 attribute which is an iterator 在数组的所有元素上::
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
索引, 索引 (reference), newaxis, ndenumerate, indices
newaxis
ndenumerate
indices
数组的形状由沿每个轴的元素数给定:
>>> a = np.floor(10 * rg.random((3, 4))) >>> a array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]]) >>> a.shape (3, 4)
数组的形状可以通过各种命令更改。请注意,以下三个命令都返回一个已修改的数组,但不更改原始数组::
>>> a.ravel() # returns the array, flattened array([3., 7., 3., 4., 1., 4., 2., 2., 7., 2., 4., 9.]) >>> a.reshape(6, 2) # returns the array with a modified shape array([[3., 7.], [3., 4.], [1., 4.], [2., 2.], [7., 2.], [4., 9.]]) >>> a.T # returns the array, transposed array([[3., 1., 7.], [7., 4., 2.], [3., 2., 4.], [4., 2., 9.]]) >>> a.T.shape (4, 3) >>> a.shape (3, 4)
数组中元素的顺序 ravel 通常是“C风格”,即最右边的索引“变化最快”,所以后面的元素 a[0, 0] 是 a[0, 1] . 如果数组被重塑为其他形状,那么数组同样被视为“C样式”。NumPy通常创建按此顺序存储的数组,因此 ravel 通常不需要复制它的参数,但是如果数组是由另一个数组的切片或使用不寻常的选项创建的,则可能需要复制它。功能 ravel 和 reshape 也可以使用可选参数指示使用FORTRAN样式的数组,其中最左边的索引更改最快。
ravel
a[0, 0]
a[0, 1]
这个 reshape 函数返回其具有已修改形状的参数,而 ndarray.resize 方法修改数组本身::
ndarray.resize
>>> a array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]]) >>> a.resize((2, 6)) >>> a array([[3., 7., 3., 4., 1., 4.], [2., 2., 7., 2., 4., 9.]])
如果尺寸给定为 -1 在整形操作中,其他尺寸将自动计算:
-1
>>> a.reshape(3, -1) array([[3., 7., 3., 4.], [1., 4., 2., 2.], [7., 2., 4., 9.]])
ndarray.shape, reshape, resize, ravel
ndarray.shape
resize
几个数组可以沿不同的轴堆叠在一起:
>>> a = np.floor(10 * rg.random((2, 2))) >>> a array([[9., 7.], [5., 2.]]) >>> b = np.floor(10 * rg.random((2, 2))) >>> b array([[1., 9.], [5., 1.]]) >>> np.vstack((a, b)) array([[9., 7.], [5., 2.], [1., 9.], [5., 1.]]) >>> np.hstack((a, b)) array([[9., 7., 1., 9.], [5., 2., 5., 1.]])
函数 column_stack 将一维数组作为列堆叠到二维数组中。它相当于 hstack 仅适用于二维阵列:
column_stack
hstack
>>> from numpy import newaxis >>> np.column_stack((a, b)) # with 2D arrays array([[9., 7., 1., 9.], [5., 2., 5., 1.]]) >>> a = np.array([4., 2.]) >>> b = np.array([3., 8.]) >>> np.column_stack((a, b)) # returns a 2D array array([[4., 3.], [2., 8.]]) >>> np.hstack((a, b)) # the result is different array([4., 2., 3., 8.]) >>> a[:, newaxis] # view `a` as a 2D column vector array([[4.], [2.]]) >>> np.column_stack((a[:, newaxis], b[:, newaxis])) array([[4., 3.], [2., 8.]]) >>> np.hstack((a[:, newaxis], b[:, newaxis])) # the result is the same array([[4., 3.], [2., 8.]])
另一方面,功能 row_stack 等于 vstack 对于任何输入数组。事实上, row_stack 是一个别名 vstack ::
row_stack
vstack
>>> np.column_stack is np.hstack False >>> np.row_stack is np.vstack True
一般来说,对于二维以上的数组, hstack 沿着第二个轴堆叠, vstack 沿着第一个轴堆叠,以及 concatenate 允许一个可选参数,给出发生连接的轴的编号。
concatenate
Note
在复杂情况下, r_ 和 c_ 用于通过沿一个轴堆叠数字来创建阵列。它们允许使用范围文字 : . ::
r_
c_
>>> np.r_[1:4, 0, 4] array([1, 2, 3, 0, 4])
将数组用作参数时, r_ 和 c_ 类似于 vstack 和 hstack 在它们的默认行为中,但是允许使用一个可选参数,给出要连接的轴的编号。
hstack, vstack, column_stack, concatenate, c_, r_
使用 hsplit ,可以沿水平轴拆分数组,方法是指定要返回的等形状数组的数目,或者指定在其后面进行拆分的列:
hsplit
>>> a = np.floor(10 * rg.random((2, 12))) >>> a array([[6., 7., 6., 9., 0., 5., 4., 0., 6., 8., 5., 2.], [8., 5., 5., 7., 1., 8., 6., 7., 1., 8., 1., 0.]]) >>> # Split `a` into 3 >>> np.hsplit(a, 3) [array([[6., 7., 6., 9.], [8., 5., 5., 7.]]), array([[0., 5., 4., 0.], [1., 8., 6., 7.]]), array([[6., 8., 5., 2.], [1., 8., 1., 0.]])] >>> # Split `a` after the third and the fourth column >>> np.hsplit(a, (3, 4)) [array([[6., 7., 6.], [8., 5., 5.]]), array([[9.], [7.]]), array([[0., 5., 4., 0., 6., 8., 5., 2.], [1., 8., 6., 7., 1., 8., 1., 0.]])]
vsplit 沿垂直轴拆分,以及 array_split 允许指定沿哪个轴拆分。
vsplit
array_split
在操作和操作数组时,它们的数据有时会被复制到新的数组中,有时则不会。对于初学者来说,这常常是一个困惑的根源。有三种情况:
简单的赋值不会复制对象或其数据。
>>> a = np.array([[ 0, 1, 2, 3], ... [ 4, 5, 6, 7], ... [ 8, 9, 10, 11]]) >>> b = a # no new object is created >>> b is a # a and b are two names for the same ndarray object True
python将可变对象作为引用传递,因此函数调用不进行复制。
>>> def f(x): ... print(id(x)) ... >>> id(a) # id is a unique identifier of an object 148293216 # may vary >>> f(a) 148293216 # may vary
不同的数组对象可以共享相同的数据。这个 view 方法创建一个新的数组对象,该对象查看相同的数据。
view
>>> c = a.view() >>> c is a False >>> c.base is a # c is a view of the data owned by a True >>> c.flags.owndata False >>> >>> c = c.reshape((2, 6)) # a's shape doesn't change >>> a.shape (3, 4) >>> c[0, 4] = 1234 # a's data changes >>> a array([[ 0, 1, 2, 3], [1234, 5, 6, 7], [ 8, 9, 10, 11]])
切片数组返回其视图::
>>> s = a[:, 1:3] >>> s[:] = 10 # s[:] is a view of s. Note the difference between s = 10 and s[:] = 10 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])
这个 copy 方法生成数组及其数据的完整副本。
copy
>>> d = a.copy() # a new array object with new data is created >>> d is a False >>> d.base is a # d doesn't share anything with a False >>> d[0, 0] = 9999 >>> a array([[ 0, 10, 10, 3], [1234, 10, 10, 7], [ 8, 10, 10, 11]])
有时 copy 如果不再需要原始数组,则应在切片后调用。例如,假设 a 是一个巨大的中间结果和最终结果 b 只包含一小部分 a ,在构造时应进行深度复制 b 切片:
a
b
>>> a = np.arange(int(1e8)) >>> b = a[:100].copy() >>> del a # the memory of ``a`` can be released.
如果 b = a[:100] 而是使用, a 被引用 b 即使 del a 执行。
b = a[:100]
del a
下面是按类别排列的一些有用的numpy函数和方法名称的列表。见 日常工作 完整的列表。
arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r_, zeros, zeros_like
eye
identity
logspace
mgrid
ogrid
ndarray.astype, atleast_1d, atleast_2d, atleast_3d, mat
ndarray.astype
atleast_1d
atleast_2d
atleast_3d
mat
array_split, column_stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, ndarray.item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack
diagonal
dsplit
dstack
ndarray.item
repeat
squeeze
swapaxes
take
all, any, nonzero, where
argmax, argmin, argsort, max, min, ptp, searchsorted, sort
ptp
searchsorted
choose, compress, cumprod, cumsum, inner, ndarray.fill, imag, prod, put, putmask, real, sum
choose
compress
ndarray.fill
imag
put
putmask
real
cov, mean, std, var
cross, dot, outer, linalg.svd, vdot
linalg.svd
广播允许通用功能以有意义的方式处理形状不完全相同的输入。
广播的第一条规则是,如果所有输入数组的维数都不相同,则会重复在较小数组的形状前面加上“1”,直到所有数组的维数都相同。
第二个广播规则确保沿特定维度的大小为1的数组的大小与沿该维度的最大形状的数组的大小相同。假定数组元素的值在“广播”数组的该维度上相同。
应用广播规则后,所有阵列的大小必须匹配。有关更多详细信息,请参见 广播 .
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 然后用这个做索引。
arr[i, j]
arr[(i, j)]
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 += 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 set :
>>> import numpy as np >>> import matplotlib.pyplot as plt >>> def mandelbrot(h, w, maxit=20): ... """Returns an image of the Mandelbrot fractal of size (h,w).""" ... y, x = np.ogrid[-1.4:1.4:h*1j, -2:0.8:w*1j] ... c = x + y * 1j ... z = c ... divtime = maxit + np.zeros(z.shape, dtype=int) ... ... for i in range(maxit): ... z = z**2 + c ... diverge = z * np.conj(z) > 2**2 # who is diverging ... div_now = diverge & (divtime == maxit) # who is diverging now ... divtime[div_now] = i # note when ... z[diverge] = 2 # avoid diverging too much ... ... return divtime >>> 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])
请注意,一维布尔数组的长度必须与要切片的维度(或轴)的长度一致。在前面的示例中, b1 长度为3 rows 在里面 a ) b2 (长度为4)适用于索引 a .
b1
b2
这个 ix_ 函数可以用来组合不同的向量,从而得到每个n-对的结果。例如,如果要计算所有a+b * c对于从每个向量a、b和c中选取的所有三元组:
ix_
>>> 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的优势在于它使用了 broadcasting rules 为了避免创建参数数组,输出的大小乘以向量的数目。
见 结构化数组 .
正在进行中。这里包括基本的线性代数。
有关更多信息,请参见numpy文件夹中的linalg.py。
>>> import numpy as np >>> a = np.array([[1.0, 2.0], [3.0, 4.0]]) >>> print(a) [[1. 2.] [3. 4.]] >>> a.transpose() array([[1., 3.], [2., 4.]]) >>> np.linalg.inv(a) array([[-2. , 1. ], [ 1.5, -0.5]]) >>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I" >>> u array([[1., 0.], [0., 1.]]) >>> j = np.array([[0.0, -1.0], [1.0, 0.0]]) >>> j @ j # matrix product array([[-1., 0.], [ 0., -1.]]) >>> np.trace(u) # trace 2.0 >>> y = np.array([[5.], [7.]]) >>> np.linalg.solve(a, y) array([[-3.], [ 4.]]) >>> np.linalg.eig(j) (array([0.+1.j, 0.-1.j]), array([[0.70710678+0.j , 0.70710678-0.j ], [0. -0.70710678j, 0. +0.70710678j]]))
Parameters: square matrix Returns The eigenvalues, each repeated according to its multiplicity. The normalized (unit "length") eigenvectors, such that the column ``v[:, i]`` is the eigenvector corresponding to the eigenvalue ``w[i]`` .
这里我们给出一个简短而有用的提示列表。
若要更改数组的尺寸,可以省略其中一个尺寸,然后自动推导:
>>> 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 ,取决于要进行堆叠的尺寸。例如::
y
m=[x;y]
>>> 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])
在两个以上维度中,这些函数背后的逻辑可能很奇怪。
面向MATLAB用户的NumPy
NumPy histogram 应用于数组的函数返回一对向量:数组的直方图和bin边的向量。当心: matplotlib 还具有一个函数来构建柱状图(称为 hist 与numpy中的不同。主要区别在于 pylab.hist 自动绘制柱状图,同时 numpy.histogram 只生成数据。
histogram
hist
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^2 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=1) # matplotlib version (plot) >>> # 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)
这个 Python tutorial
数字参考
SciPy Tutorial
SciPy Lecture Notes
A matlab, R, IDL, NumPy/SciPy dictionary