numpy
Numpy基础
numpy 的主要对象是多维数组,其元素的类型相同,并通过非负整数索引。
在numpy中,维度被称之为 轴。
例如,点 a 在3D空间中的坐标 [1, 2, 1] 有一根轴,轴的长度为3。
下图的数组有两根轴,第一根的长度为2,第二根的长度为3
[
[ 1., 0., 0.],
[ 0., 1., 2.]
]
ndarry
numpy的array类叫做 ndarray,也称为 array。
ndarray 有一些重要的属性:
ndarray.ndim
轴的个数
ndarray.shape
一个整数元组,表示数组在每个维度中的大小。
一个n行m列的矩阵,shape将返回 (n,m)。
元组的长度就是ndim(轴的个数)
ndarray.size
数组中所有元素的个数,等于shape各项之积。
ndarray.dtype
描述元素类型的对象。
除了能使用python标准类型之外. 还可以使用numpy自带的类型:
numpy.int32, numpy.int16, numpy.float64 ...
ndarray.itemsize
数组中每个元素的大小(以字节为单位)。
example
>>> 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'>
创建数组
np.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')
>>> c = np.array( [ [1,2], [3,4] ], dtype=complex ) # 可以指定数据类型
>>> c
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
np.zeros( ) , np.ones( ), np.empty( )
>>> 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 ) # dtype can also be specified
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) ) # uninitialized
array([[ 3.73603959e-262, 6.02658058e-154, 6.55490914e-260], # may vary
[ 5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])
np.arange( )
用法类似python的range
>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])
>>> np.arange( 0, 2, 0.3 ) # 支持浮点数参数
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
np.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)
输出数组
如果数组太大,打印时自动隐藏中间的。可以使用以下方法强制打印全部
>>> np.set_printoptions(threshold=sys.maxsize) # 需导入sys库
基础运算
算数运算会作用在每一个元素上,并返回新数组
>>>
>>> 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])
>>> 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]])
Some operations, such as += and *=, act in place to modify an existing array rather than create a new one.
>>> 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.UFuncTypeError: 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
通过指定轴参数,可以沿指定轴应用操作:
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]])
索引 切片 迭代
可以对一维数组进行索引、切片和迭代,就像列表和其他 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])
根据第一根轴进行迭代:
>>> 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]
按元素迭代
>>> for element in b.flat:
... print(element)
...
0
1
2
3
10
.
.
.
变形
改变数组的形状
数组的形状是由每个轴上的元素数量决定的:
>>> 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() # 把数组摊平
array([3., 7., 3., 4., 1., 4., 2., 2., 7., 2., 4., 9.])
>>> a.reshape(6,2)
array([[3., 7.],
[3., 4.],
[1., 4.],
[2., 2.],
[7., 2.],
[4., 9.]])
>>> a.T # 转置
array([[3., 1., 7.],
[7., 4., 2.],
[3., 2., 4.],
[4., 2., 9.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)
reshape 不改变源数组, 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,则其他维度将自动计算:
>>> a.reshape(3,-1)
array([[3., 7., 3., 4.],
[1., 4., 2., 2.],
[7., 2., 4., 9.]])
合并数组
多个数组可以按不同的轴合并
>>> 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
>>> 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.]])
拆分数组
Using hsplit, you can split an array along its horizontal axis, either by specifying the number of equally shaped arrays to return, or by specifying the columns after which the division should occur:
>>> 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 splits along the vertical axis, and array_split allows one to specify along which axis to split.
Copies and Views
在操作和操作数组时,它们的数据有时会被复制到新的数组中,有时则不会。这对于初学者来说常常是一个困惑的来源。有三种情况:
一点没COPY
>>> 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
视图 or 浅拷贝
不同的数组对象可以共享相同的数据。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] # 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]])
深拷贝
完全复制一个
>>> 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 的时候,应该做一个Deep Copy:
>>> a = np.arange(int(1e8))
>>> b = a[:100].copy()
>>> del a # the memory of ``a`` can be released.
浙公网安备 33010602011771号