NumPy 介绍
什么是 NumPy?
NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。
NumPy包的核心是 ndarray 对象。它封装了python原生的同数据类型的 n 维数组,为了保证其性能优良,其中有许多操作都是代码在本地进行编译后执行的。
NumPy数组 和 原生Python Array(数组)之间有几个重要的区别:
- NumPy 数组在创建时具有固定的大小,与Python的原生数组对象(可以动态增长)不同。更改ndarray的大小将创建一个新数组并删除原来的数组。
- NumPy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。 例外情况:Python的原生数组里包含了NumPy的对象的时候,这种情况下就允许不同大小元素的数组。
- NumPy 数组有助于对大量数据进行高级数学和其他类型的操作。通常,这些操作的执行效率更高,比使用Python原生数组的代码更少。
- 越来越多的基于Python的科学和数学软件包使用NumPy数组; 虽然这些工具通常都支持Python的原生数组作为参数,但它们在处理之前会还是会将输入的数组转换为NumPy的数组,而且也通常输出为NumPy数组。换句话说,为了高效地使用当今科学/数学基于Python的工具(大部分的科学计算工具),你只知道如何使用Python的原生数组类型是不够的 - 还需要知道如何使用 NumPy 数组。
关于数组大小和速度的要点在科学计算中尤为重要。举一个简单的例子,考虑将1维数组中的每个元素与相同长度的另一个序列中的相应元素相乘的情况。如果数据存储在两个Python 列表 a
和 b
中,我们可以迭代每个元素,如下所示:
start_time=time.time()
n=10**6
a=list(range(n))
b=list(range(n,-1,-1))
c = []
for i in range(len(a)):
c.append(a[i]*b[i])
end_time=time.time()
print('时间:',end_time-start_time)
#n=10**8 时间: 20.796018600463867
NumPy 为我们提供了两全其美的解决方案:当涉及到 ndarray 时,逐个元素的操作是“默认模式”,但逐个元素的操作由预编译的C代码快速执行。在NumPy中:
start_time=time.time()
a=np.arange(n)
b=np.arange(n)
c = a*b
end_time=time.time()
print('时间:',end_time-start_time)
# 时间: 1.9287562370300293
快了近10倍
以近C速度执行前面的示例所做的事情,但是我们期望基于Python的代码具有简单性。的确,NumPy的语法更为简单!最后一个例子说明了NumPy的两个特征,它们是NumPy的大部分功能的基础:矢量化和广播。
为什么 NumPy 这么快?
矢量化描述了代码中没有任何显式的循环,索引等 - 这些当然是预编译的C代码中“幕后”优化的结果。矢量化代码有许多优点,其中包括:
- 矢量化代码更简洁,更易于阅读
- 更少的代码行通常意味着更少的错误
- 代码更接近于标准的数学符号(通常,更容易正确编码数学结构)
- 矢量化导致产生更多 “Pythonic” 代码。如果没有矢量化,我们的代码就会被低效且难以阅读的
for
循环所困扰。
广播是用于描述操作的隐式逐元素行为的术语; 一般来说,在NumPy中,所有操作,不仅仅是算术运算,而是逻辑,位,功能等,都以这种隐式的逐元素方式表现,即它们进行广播。此外,在上面的例子中,a
并且b
可以是相同形状的多维数组,或者标量和数组,或者甚至是具有不同形状的两个数组,条件是较小的数组可以“扩展”到更大的形状。结果广播明确无误的方式。
快速入门教程
基础知识
NumPy的主要对象是同构多维数组。它是一个元素表(通常是数字),所有类型都相同,由非负整数元组索引。在NumPy维度中称为 轴 。
例如,3D空间中的点的坐标[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 - 数组的轴(维度)的个数。在Python世界中,维度的数量被称为rank。
- ndarray.shape - 数组的维度。这是一个整数的元组,表示每个维度中数组的大小。对于有 n 行和 m 列的矩阵,
shape
将是(n,m)
。因此,shape
元组的长度就是rank或维度的个数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 - 该缓冲区包含数组的实际元素。通常,我们不需要使用此属性,因为我们将使用索引访问数组中的元素。
# ndarray.ndim - 数组的轴(维度)的个数, 这里是2
print(arr.ndim)
# ndarray.shape - 一个表示数组在每个维度上大小的整数元组,这里是(2, 3)
print(arr.shape)
# ndarray.size - 数组元素的总数,这里是 2 * 3 = 6
print(arr.size)
# ndarray.dtype - 数组中元素的类型,默认是int32
print(arr.dtype)
# ndarray.itemsize - 每个元素的字节大小,int32的元素大小是4字节,32/8
print(arr.itemsize)
# ndarray.data - 包含实际数组元素的缓冲区,通常不直接使用
print(arr.data)
3
(1, 3, 4)
12
int32
4
<memory at 0x000001CCD5C7F4F0>
数组创建
有几种方法可以创建数组。
例如,你可以使用array函数从常规Python列表或元组中创建数组。得到的数组的类型是从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
>>> 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
创建一个由0组成的数组,函数 ones
创建一个完整的数组,函数empty
创建一个数组,其初始内容是随机的,取决于内存的状态。默认情况下,创建的数组的dtype是 float64
类型的。
a=np.zeros((3,4))
print(a,a.dtype)
a=np.ones((2,5))
print(a,a.dtype)
a=np.empty((2,5))
print(a,a.dtype)
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]] float64
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]] float64
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]] float64
为了创建数字组成的数组,NumPy提供了一个类似于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
函数来接收我们想要的元素数量的函数,而不是步长(step):
a=np.linspace(0,2,10)
print(a)
x=np.linspace(0,2*np.pi,10)
print(x)
np.sin(x)
[0. 0.22222222 0.44444444 0.66666667 0.88888889 1.11111111
1.33333333 1.55555556 1.77777778 2. ]
[0. 0.6981317 1.3962634 2.0943951 2.7925268 3.4906585
4.1887902 4.88692191 5.58505361 6.28318531]
array([ 0.00000000e+00, 6.42787610e-01, 9.84807753e-01, 8.66025404e-01,
3.42020143e-01, -3.42020143e-01, -8.66025404e-01, -9.84807753e-01,
-6.42787610e-01, -2.44929360e-16])
另见这些API
# 从列表创建数组
arr = np.array([1, 2, 3])
# 创建全0数组,形状为(2,3)
zeros_arr = np.zeros((2,3))
# 创建一个与已有数组形状相同的全0数组
zeros_like_arr = np.zeros_like(arr)
# 创建全1数组,形状为(3,2)
ones_arr = np.ones((3,2))
# 创建与另一个数组形状相同的全1数组
ones_like_arr = np.ones_like(zeros_arr)
# 创建未初始化的数组,元素为随机值
empty_arr = np.empty((2,2))
# 创建指定范围的数组,包括2, 6范围
arange_arr = np.arange(2, 7)
# 创建一个开始于0,结束于2π,且元素个数为5的等步长数组
linspace_arr = np.linspace(0, 2*np.pi, 5)
返回指定间隔内均匀分布的数字。
返回 num 个均匀间隔的样本,在间隔 [start, stop] 上计算。
可以选择排除间隔的端点。
# 创建指定形状的随机数数组,数值在[0,1)之间
rand_arr = np.random.rand(2, 3)
# 创建标准正态分布的随机数数组
randn_arr = np.random.randn(2, 3)
# 从已有函数创建数组,函数作用于索引
def func(x, y):
return x + y
fromfunc_arr = np.fromfunction(func, (3,3))
打印数组
当您打印数组时,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
某些操作(例如`+=`和 `*=`)会更直接更改被操作的矩阵数组而不会创建新矩阵数组。
>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
[3, 3, 3]])
>>> b += a
array([[ 3.417022 , 3.72032449, 3.00011437],
[ 3.30233257, 3.14675589, 3.09233859]])
>>> a += b # b is not automatically converted to integer type
Traceback (most recent call last):
...
TypeError: 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
array([ 1. , 2.57079633, 4.14159265])
>>> c.dtype.name
>>> 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 = np.random.random((2,3))
array([[ 0.18626021, 0.34556073, 0.39676747],
[ 0.53881673, 0.41919451, 0.6852195 ]])
>>> a.sum()
2.5718191614547998
>>> a.min()
0.1862602113776709
>>> a.max()
0.6852195003967595
默认情况下,这些操作适用于数组,就像它是一个数字列表一样,无论其形状如何。但是,通过指定`axis` 参数,您可以沿数组的指定轴应用操作:
>>> b = np.arange(12).reshape(3,4)
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():检查数组中的元素是否全部为True,返回布尔值
any():检查数组中的元素是否有任意一个为True,返回布尔值
argmax():返回数组中最大值元素的索引位置
argmin():返回数组中最小值元素的索引位置
mean():计算数组中元素的算术平均值
std():计算数组中元素的标准差
sum():数组元素的总和
sort():对数组进行排序
reshape():改变数组的形状
transpose():数组转置
clip():元素裁剪到指定区间
argmax():返回数组中最大值元素的索引
nonzero():返回数组中非零元素的索引
索引、切片和迭代
一维的数组可以进行索引、切片和迭代操作的,就像 列表open in new window 和其他Python序列类型一样。
**一维**的数组可以进行索引、切片和迭代操作的,就像 [列表open in new window](https://docs.python.org/tutorial/introduction.html#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])
>>> a[:6:2] = -1000 # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -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.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0
**多维**的数组每个轴可以有一个索引。这些索引以逗号分隔的元组给出:
def f(x,y):
y+=1
return x**y
a=np.fromfunction(f,(3,5))
print(a)
[[ 0. 0. 0. 0. 0.]
[ 1. 1. 1. 1. 1.]
[ 2. 4. 8. 16. 32.]]
>>> 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` 是rank为5的数组(即,它具有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]])
对多维数组进行 **迭代(Iterating)** 是相对于第一个轴完成的:
>>> 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`属性,该属性是数组的所有元素的[迭代器open in new window](https://docs.python.org/tutorial/classes.html#iterators):
>>> 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
形状操纵
改变数组的形状
一个数组的形状是由每个轴的元素数量决定的:
>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
>>> a.shape
(3, 4)
可以使用各种命令更改数组的形状。请注意,以下三个命令都返回一个修改后的数组,但不会更改原始数组:
>>> a.ravel() # returns the array, flattened
array([ 2., 8., 0., 6., 4., 5., 1., 1., 8., 9., 3., 6.])
>>> a.reshape(6,2) # returns the array with a modified shape
array([[ 2., 8.],
[ 0., 6.],
[ 4., 5.],
[ 1., 1.],
[ 8., 9.],
[ 3., 6.]])
>>> a.T # returns the array, transposed
array([[ 2., 4., 8.],
[ 8., 5., 9.],
[ 0., 1., 3.],
[ 6., 1., 6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)
r=10*np.random.random((2,5))
print(r)
a = np.floor(r)
print(a)
a = np.ceil(r)
print(a)
# floor在英文中是地板的意思,而ceil是天花板的意思
print(a.ravel())
# 返回连续的展平数组。
# 返回包含输入元素的一维数组。仅在需要时才制作副本。
# 从 NumPy 1.10 开始,返回的数组将与输入数组具有相同的类型。 (例如,对于屏蔽数组输入,将返回屏蔽数组)
print(a.reshape(1,10))
print(a.T,a.T.shape)
[[9.08077382 3.24237761 3.72397674 3.44720592 8.00126208]
[4.10737257 2.1255163 1.9829024 1.38653589 5.77261939]]
[[9. 3. 3. 3. 8.]
[4. 2. 1. 1. 5.]]
[[10. 4. 4. 4. 9.]
[ 5. 3. 2. 2. 6.]]
[10. 4. 4. 4. 9. 5. 3. 2. 2. 6.]
[[10. 4. 4. 4. 9. 5. 3. 2. 2. 6.]]
[[10. 5.]
[ 4. 3.]
[ 4. 2.]
[ 4. 2.]
[ 9. 6.]] (5, 2)
由 ravel() 产生的数组中元素的顺序通常是“C风格”,也就是说,最右边的索引“变化最快”,因此[0,0]之后的元素是[0,1] 。如果将数组重新整形为其他形状,则该数组将被视为“C风格”。NumPy通常创建按此顺序存储的数组,因此 ravel() 通常不需要复制其参数,但如果数组是通过获取另一个数组的切片或使用不常见的选项创建的,则可能需要复制它。还可以使用可选参数指示函数 ravel() 和 reshape(),以使用FORTRAN样式的数组,其中最左边的索引变化最快。
>>> a
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
>>> a.resize((2,6))
>>> a
array([[ 2., 8., 0., 6., 4., 5.],
[ 1., 1., 8., 9., 3., 6.]])
如果在 reshape 操作中将 size 指定为-1,则会自动计算其他的 size 大小:
>>> a.reshape(3,-1)
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
将不同数组堆叠在一起
几个数组可以沿不同的轴堆叠在一起,例如:
a=np.arange(4).reshape(2,2)
b=np.arange(4).reshape(2,2)
print(np.vstack((a,b)))
print(np.hstack((a,b)))
print(np.column_stack((a,b)))
print(a[:np.newaxis])
c=np.arange(24).reshape((2,3,4))
print(c[1,2,3])
print(c[1,2,1:3])
[[0 1]
[2 3]
[0 1]
[2 3]]
[[0 1 0 1]
[2 3 2 3]]
[[0 1 0 1]
[2 3 2 3]]
[[0 1]
[2 3]]
23
[21 22]
几个数组可以沿不同的轴堆叠在一起,例如:
>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8., 8.],
[ 0., 0.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1., 8.],
[ 0., 4.]])
>>> np.vstack((a,b))
array([[ 8., 8.],
[ 0., 0.],
[ 1., 8.],
[ 0., 4.]])
>>> np.hstack((a,b))
array([[ 8., 8., 1., 8.],
[ 0., 0., 0., 4.]])
该函数将[`column_stack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.column_stack.html#numpy.column_stack) 1D数组作为列堆叠到2D数组中。它仅相当于 [`hstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.hstack.html#numpy.hstack)2D数组:
>>> from numpy import newaxis
>>> np.column_stack((a,b)) # with 2D arrays
array([[ 8., 8., 1., 8.],
[ 0., 0., 0., 4.]])
>>> 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] # this allows to have a 2D columns 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.]])
另一方面,该函数[`ma.row_stack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.ma.row_stack.html#numpy.ma.row_stack)等效[`vstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.vstack.html#numpy.vstack) 于任何输入数组。通常,对于具有两个以上维度的数组, [`hstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.hstack.html#numpy.hstack)沿其第二轴[`vstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.vstack.html#numpy.vstack)堆叠,沿其第一轴堆叠,并[`concatenate`open in new window](https://numpy.org/devdocs/reference/generated/numpy.concatenate.html#numpy.concatenate) 允许可选参数给出连接应发生的轴的编号。
**注意**
在复杂的情况下,[`r_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.r_.html#numpy.r_)和c [`c_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.c_.html#numpy.c_)于通过沿一个轴堆叠数字来创建数组很有用。它们允许使用范围操作符(“:”)。
>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])
与数组一起用作参数时, [`r_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.r_.html#numpy.r_) 和 [`c_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.c_.html#numpy.c_) 在默认行为上类似于 [`vstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.vstack.html#numpy.vstack) 和 [`hstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.hstack.html#numpy.hstack) ,但允许使用可选参数给出要连接的轴的编号。
另见
[`hstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.hstack.html#numpy.hstack), [`vstack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.vstack.html#numpy.vstack), [`column_stack`open in new window](https://numpy.org/devdocs/reference/generated/numpy.column_stack.html#numpy.column_stack), [`concatenate`open in new window](https://numpy.org/devdocs/reference/generated/numpy.concatenate.html#numpy.concatenate), [`c_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.c_.html#numpy.c_), [`r_`open in new window](https://numpy.org/devdocs/reference/generated/numpy.r_.html#numpy.r_)
将一个数组拆分成几个较小的数组
使用hsplitopen in new window,可以沿数组的水平轴拆分数组,方法是指定要返回的形状相等的数组的数量,或者指定应该在其之后进行分割的列:
a = np.floor(10*np.random.random((2,12)))
print(a)
print(np.hsplit(a,3) ) # Split a into 3
for i in np.hsplit(a,3):
print(i.shape)
print(np.hsplit(a,(3,4))) # Split a after the third and the fourth column
for i in np.hsplit(a,(3,4)):
print(i.shape)
[[9. 1. 8. 7. 8. 1. 4. 0. 4. 5. 1. 4.]
[9. 0. 9. 6. 4. 8. 8. 3. 6. 2. 1. 5.]]
[array([[9., 1., 8., 7.],
[9., 0., 9., 6.]]), array([[8., 1., 4., 0.],
[4., 8., 8., 3.]]), array([[4., 5., 1., 4.],
[6., 2., 1., 5.]])]
(2, 4)
(2, 4)
(2, 4)
[array([[9., 1., 8.],
[9., 0., 9.]]), array([[7.],
[6.]]), array([[8., 1., 4., 0., 4., 5., 1., 4.],
[4., 8., 8., 3., 6., 2., 1., 5.]])]
(2, 3)
(2, 1)
(2, 8)
使用[`hsplit`open in new window](https://numpy.org/devdocs/reference/generated/numpy.hsplit.html#numpy.hsplit),可以沿数组的水平轴拆分数组,方法是指定要返回的形状相等的数组的数量,或者指定应该在其之后进行分割的列:
>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9., 5., 6., 3., 6., 8., 0., 7., 9., 7., 2., 7.],
[ 1., 4., 9., 2., 2., 1., 0., 6., 2., 2., 4., 0.]])
>>> np.hsplit(a,3) # Split a into 3
[array([[ 9., 5., 6., 3.],
[ 1., 4., 9., 2.]]), array([[ 6., 8., 0., 7.],
[ 2., 1., 0., 6.]]), array([[ 9., 7., 2., 7.],
[ 2., 2., 4., 0.]])]
>>> np.hsplit(a,(3,4)) # Split a after the third and the fourth column
[array([[ 9., 5., 6.],
[ 1., 4., 9.]]), array([[ 3.],
[ 2.]]), array([[ 6., 8., 0., 7., 9., 7., 2., 7.],
[ 2., 1., 0., 6., 2., 2., 4., 0.]])]
[`vsplit`open in new window](https://numpy.org/devdocs/reference/generated/numpy.vsplit.html#numpy.vsplit)沿垂直轴分割,并[`array_split`open in new window](https://numpy.org/devdocs/reference/generated/numpy.array_split.html#numpy.array_split)允许指定要分割的轴。
拷贝和视图
当计算和操作数组时,有时会将数据复制到新数组中,有时则不会。这通常是初学者混淆的根源。有三种情况:
完全不复制
简单分配不会复制数组对象或其数据。
>>> a = np.arange(12)
>>> b = a # no new object is created
>>> b is a # a and b are two names for the same ndarray object
True
>>> b.shape = 3,4 # changes the shape of a
>>> a.shape
(3, 4)
Python将可变对象作为引用传递,因此函数调用不会复制。
>>> def f(x):
... print(id(x))
...
>>> id(a) # id is a unique identifier of an object
148293216
>>> f(a)
148293216
视图或浅拷贝
不同的数组对象可以共享相同的数据。该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.shape = 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] # spaces added for clarity; could also be written "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
方法生成数组及其数据的完整副本。
>>> 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 = np.arange(int(1e8))
>>> b = a[:100].copy()
>>> del a # the memory of ``a`` can be released.
如果改为使用 b = a[:100]
,则 a
由 b
引用,并且即使执行 del a
也会在内存中持久存在。
功能和方法概述
以下是按类别排序的一些有用的NumPy函数和方法名称的列表。有关完整列表,请参阅参考手册里的常用API。
Less 基础
广播(Broadcasting)规则
广播允许通用功能以有意义的方式处理不具有完全相同形状的输入。
广播的第一个规则是,如果所有输入数组不具有相同数量的维度,则将“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] # i.e., a[ : , j]
array([[[ 2, 1],
[ 3, 3]],
[[ 6, 5],
[ 7, 7]],
[[10, 9],
[11, 11]]])
当然,我们可以按顺序(比如列表)放入i
,j
然后使用列表进行索引。
>>> l = [i,j]
>>> a[l] # equivalent to a[i,j]
array([[ 2, 5],
[ 7, 11]])
但是,我们不能通过放入i
和j
放入数组来实现这一点,因为这个数组将被解释为索引a的第一个维度。
>>> s = np.array( [i,j] )
>>> a[s] # not what we want
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: index (3) out of range (0<=index<=2) in dimension 0
>>>
>>> a[tuple(s)] # same as a[i,j]
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]])
>>>
>>> ind = data.argmax(axis=0) # index of the maxima for each series
>>> ind
array([2, 0, 3, 1])
>>>
>>> time_max = time[ind] # times corresponding to the maxima
>>>
>>> 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集open in new window的图像:
>>> 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))
>>> plt.show()
使用布尔值进行索引的第二种方法更类似于整数索引; 对于数组的每个维度,我们给出一个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
。
函数
ix_open in new window函数可用于组合不同的向量,以便获得每个n-uplet的结果。例如,如果要计算从每个向量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的优点是它利用了广播规则 ,以避免创建一个参数数组,输出的大小乘以向量的数量。
import numpy as np
# 创建两个数组
x = np.array([1, 2, 3])
y = np.array([3, 5, 7])
# 用np.ix_生成网格索引
X, Y = np.ix_(x, y)
# X和Y都是二维数组,可以用于索引
print(X)
# [[1 1 1]
# [2 2 2]
# [3 3 3]]
print(Y)
# [[3 5 7]
# [3 5 7]
# [3 5 7]]
# 用网格索引进行数组操作
A = np.arange(9).reshape(3, 3)
B = A[X, Y]
print(B)
# [[3 4 5]
# [6 7 8]
# [9 10 11]]
# B是A的部分元素组成的新数组
a = np.array([2,3,4,5])
b = np.array([8,5,4])
c = np.array([5,4,6,8,3])
A,B,C=np.ix_(a,b,c)
print(A,B,C)
print(A+B*C)
[[[2]]
[[3]]
[[4]]
[[5]]] [[[8]
[5]
[4]]] [[[5 4 6 8 3]]]
[[[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]]]
np.ix_可以通过两个一维数组生成二维的网格索引,常用于提取数组的部分元素。
行索引X和列索引Y配合使用,可以从原数组A中选取元素放入新数组B中。
这样避免了使用Python列表推导式或嵌套for循环的繁琐。np.ix_实现了一个清晰简洁的数组索引方式。
使用字符串建立索引
请参见结构化数组。
线性代数
工作正在进行中。这里包括基本线性代数。
简单数组操作
有关更多信息,请参阅numpy文件夹中的linalg.py.
a = np.array([[1.0, 2.0], [3.0, 4.0]]) # 创建一个2x2数组
print(a) # 打印数组
print(a.transpose() ) # 数组转置
b=np.linalg.inv(a)
print(np.linalg.inv(a) ) # 计算数组的逆矩阵
print('逆矩阵',a@b)
u = np.eye(2) # 创建2x2的单位矩阵
print(u) # 打印单位矩阵
j = np.array([[0.0, -1.0], [1.0, 0.0]]) # 创建2x2数组j
print(j @ j ) # 矩阵乘法,相当于j.dot(j)
print(np.trace(u)) # 计算矩阵的迹
y = np.array([[5.],[7.]]) # 创建数组y
print(np.linalg.solve(a, y)) # 求解线性方程组 Ax = y
print(np.linalg.eig(j) ) # 求矩阵的特征值和特征向量
[[1. 2.]
[3. 4.]]
[[1. 3.]
[2. 4.]]
[[-2. 1. ]
[ 1.5 -0.5]]
逆矩阵 [[1.0000000e+00 0.0000000e+00]
[8.8817842e-16 1.0000000e+00]]
[[1. 0.]
[0. 1.]]
[[-1. 0.]
[ 0. -1.]]
2.0
[[-3.]
[ 4.]]
(array([0.+1.j, 0.-1.j]), array([[0.70710678+0.j , 0.70710678-0.j ],
[0. -0.70710678j, 0. +0.70710678j]]))
>>> 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.00000000-0.70710678j, 0.00000000+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)
>>> a.shape = 2,-1,3 # -1 means "whatever is needed"
>>> a.shape
(2, 5, 3)
>>> a
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) # x=([0,2,4,6,8])
y = np.arange(5) # y=([0,1,2,3,4])
m = np.vstack([x,y]) # m=([[0,2,4,6,8],
# [0,1,2,3,4]])
xy = np.hstack([x,y]) # xy =([0,2,4,6,8,0,1,2,3,4])
这些函数背后的逻辑在两个以上的维度上可能很奇怪。
另见
与 Matlab 比较
直方图
histogram
应用于数组的NumPy 函数返回一对向量:数组的直方图和bin的向量。注意: matplotlib
还有一个构建直方图的功能(hist
在Matlab中称为),与NumPy中的直方图不同。主要区别在于pylab.hist
自动绘制直方图,而 numpy.histogram
只生成数据。
>>> import numpy as np
>>> 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 = np.random.normal(mu,sigma,10000)
>>> # Plot a normalized histogram with 50 bins
>>> plt.hist(v, bins=50, density=1) # matplotlib version (plot)
>>> plt.show()
>>> # 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)
>>> plt.show()
参考资料:
NumPy