NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种例程,包括数学,逻辑,形状操作,排序,选择,I / O离散傅立叶变换,基本线性代数,基本统计运算,随机模拟等等。
numpy的设计使得它可以以简洁的编码实现近似c般的执行速度
NumPy的两个关键特征,它们是numpy大部分功能的基础:矢量化和广播。
矢量化代码有许多优点,其中包括:
- 矢量化代码更简洁,更易于阅读
- 更少的代码行通常意味着更少的错误
- 代码更接近于标准的数学符号(通常,更容易,正确编码数学结构)
- 矢量化导致更多“Pythonic”代码。如果没有矢量化,我们的代码就会被低效且难以阅读的
for
循环所困扰。
广播是用于描述操作的隐式逐元素行为的术语; 一般来说,在NumPy中,所有操作,不仅仅是算术运算,而是逻辑,位,功能等,都以这种隐式的逐元素方式表现,即它们进行广播。
NumPy的数组类被ndarray调用
ndarray
对象更重要的属性是:
- ndarray.ndim
- 阵列的轴数(尺寸)。#其实就是数据维数,在NumPy维度中称为轴
- 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
- 包含数组实际元素的缓冲区。通常,我们不需要使用此属性,因为我们将使用索引工具访问数组中的元素。
创建数组,可以使用array
函数从常规Python列表或元组创建数组。结果数组的类型是从序列中元素的类型推导出来的。
import numpy as np
a = np.array([1,2,3]) #接受传入列表
b = np.array((1,2,3)) #接受传入元组
c = np.array(15) #我试了一下,还接受传入数字,得到array(15)的0维数据,
d = np.array(1,2,3) #不接受直接传入数字数字列
通常,数组的元素最初是未知的,但其大小是已知的。因此,NumPy提供了几个函数来创建具有初始占位符内容的数组。该函数zeros
创建一个充满零的数组,该函数 ones
创建一个充满1的数组,该函数empty
创建一个数组,其初始内容是随机的,并取决于内存的状态。默认情况下,创建的数组的dtype是 float64
。
zeros(2,3) #创建一个2行3列的0.元素阵列
为了创建数字序列,NumPy提供了一个arange()函数
np.arange( 0, 2, 0.3 ) # it accepts float arguments,这个好玩,是python内置的range的加强版
array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
当arange
与浮点参数一起使用时,由于有限的浮点精度,通常无法预测获得的元素数量。出于这个原因,通常最好使用linspace
作为参数接收我们想要的元素数量的函数,这里的意思是说在浮点参数下你想要得到一个确定的元素数量用arange就不行了,这时最好用np.linspace,传入的第三个参数不再是步长,而是你想获得的元素数量,如np.linspace(0,pi,100)
numpy.random.
rand
(d0,d1,...,dn ) #[0,1)随机抽样函数,输入目标矩阵shape得到均匀分布的0-1间随机数填充的矩阵
给定形状的随机值。
创建给定形状的数组,并使用来自均匀分布的随机样本填充它。[0, 1)
numpy.random.
randn
(d0,d1,...,dn )
从“标准正态”分布中返回一个样本(或样本)。
如果提供了正数,int_like或int-convertible参数,则 randn
生成一个形状数组,填充从均值0和方差1的单变量“正态”(高斯)分布中采样的随机浮点数(如果有任何浮点数,则它们是第一个通过截断转换为整数)。如果没有提供参数,则返回从分布中随机抽样的单个float。
对于随机样本,请使用:
σ * np.random.randn(...) + μ
来自N(3,6.25)的2乘4的样本数组:
>>> 2.5 * np.random.randn(2, 4) + 3 array([[-4.49401501, 4.00950034, -1.81814867, 7.29718677], #random [ 0.39924804, 4.68456316, 4.99394529, 4.84057254]]) #random
如果数组太大而无法打印,NumPy会自动跳过数组的中心部分并仅打印角落
要禁用此行为并强制NumPy打印整个阵列,可以使用更改打印选项set_printoptions
。
>>> np.set_printoptions(threshold=np.nan)
基操部分
数组上的算术运算符应用于元素。创建一个新数组并填充结果。这就是广播的含义,数组运算传递给内部每个元素
与许多矩阵语言不同,运算符*
在NumPy数组中以元素方式运行。矩阵乘积可以使用@
运算符(在python> = 3.5中)或dot
函数或方法执行
当使用不同类型的数组进行操作时,结果数组的类型对应于更一般或更精确的数组(称为向上转换的行为),这个也好理解,数组A元素为int,数组B元素为float,
A和B做运算时结果数组元素会是float,这就是更精确、向上转换,numpy里进行向下转换如float变为int会报错
许多一元操作,例如计算数组中所有元素的总和,都是作为ndarray
类的方法实现的。如数组a,a.sum()计算a的元素和,还有a.max()、a.min()
默认情况下,这些操作适用于数组,就像它是一个数字列表一样,无论其形状如何。但是,通过指定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.])
一维数组可以被索引,切片和迭代,就像 列表 和其他Python序列一样
多维数组每个轴可以有一个索引。这些索引以逗号分隔的元组给出
对多维数组进行迭代是针对第一个轴完成的
如果想要对数组中的每个元素执行操作,可以使用flat
属性 作为数组的所有元素的 迭代器
b = np.arange(8).reshape(2,4)
b
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
for row in b:
print(row)
[0 1 2 3]
[4 5 6 7]
for element in b.flat:
print(element)
0
1
2
3
4
5
6
7
形状操作
改变数组形状
a.reshape(2,4) 返回形状改为2*4的数组但不改变a,a.T对a做转置,而该 ndarray.resize
方法修改数组本身
几个阵列可以沿不同的轴堆叠在一起:
>>> 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.]])
堆叠不同的数组
不同轴向的堆叠:
>>> a
array([[ 8., 8.],
[ 0., 0.]])
>>> 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.]])
r_和c_用法
>>> np.r_[1:4,0,4] array([1, 2, 3, 0, 4])
np.c_[np.array([1,2,3]), np.array([4,5,6])] array([[1, 4], [2, 5], [3, 6]])
查看或浅拷贝
不同的数组对象可以共享相同的数据。该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]])
广播规则
广播允许通用功能以有意义的方式处理不具有完全相同形状的输入。
广播的第一个规则是,如果所有输入数组不具有相同数量的维度,则将“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 "", 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集的图像:
>>> 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_()函数
该ix_
函数可用于组合不同的向量,以便获得每个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的优点是它利用了广播规则 ,以避免创建一个参数数组,输出的大小乘以向量的数量。
直方图
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()
文档阅读书签:https://docs.scipy.org/doc/numpy/user/quickstart.html