简介
NumPy全称Numeric Python,它具有如下特性: - ndarray(多维数组对象),即对n维数组的基本操作 - 与ndarray相关的各种运算 - 支持I/O操作 - 线性代数、随机数、傅里叶变换等操作 - 与C/C++/Fortran等编程语言结合
NumPy是专门为大型数组的相关操作所设计的函数库,它的底层为C语言。同时在内存分配上也是为数组开辟连续的空间进行存储。通过这些优化,使得其运行速度相比于Python的内置类型要快得多。
NumPy官方文档:https://docs.scipy.org/doc/numpy/
1 2 3
| import numpy as np import warnings warnings.filterwarnings("ignore")
|
ndarray
创建
非随机方式
在NumPy中,创建一个ndarray对象的方法有很多,下面为一些示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| data=[[1,2,3,4],[5,6,7,8]] data1=np.array(data,dtype=np.int64) data2=np.asarray(data) data3=np.arange(1,100,2) data4=np.ones((3,3)) data5=np.ones_like(data1) data6=np.zeros([2,2,2]) data7=np.zeros_like(data1) data8=np.empty((2,2)) data9=np.empty_like(data1) data10=np.eye(4) data11=np.identity(3) data12=np.full((2,2),3) data13=np.full_like(data1,3) data14=np.linspace(0.0,2.0,4)
|
其中,每个ndarray都有如下的属性:
2
(2, 4)
dtype('int64')
ndarray可以使用的数据类型如下:
int8, uint8 |
有符号和无符号的8位整数 |
int16, uint16 |
有符号和无符号的16位整数 |
int32, uint32 |
有符号和无符号的32位整数 |
int64, uint64 |
有符号和无符号的64位整数 |
float16 |
半精度浮点数 |
float32 |
单精度浮点数 |
float64 |
双精度浮点数 |
float128 |
扩展精度的浮点数 |
complex64, complex128, complex256 |
使用32、64和128位浮点数表示的复数 |
bool |
布尔类型 |
object |
Python的对象类型 |
string_ |
固定长度的字符串类型 |
unicode_ |
固定长度的unicode类型 |
1
| data1=data1.astype('string_')
|
dtype('S21')
一个ndarray的数据类型可以自己定义,例如:
1
| dtype_self=[('x',np.float64),('y',np.int32)]
|
1
| self_arr=np.array([(1.5,6),(np.pi,-2)],dtype=dtype_self)
|
array([(1.5 , 6), (3.14159265, -2)],
dtype=[('x', '<f8'), ('y', '<i4')])
3.141592653589793
(3.14159265, -2)
array([ 6, -2])
在数据类型的定义上面比较灵活,支持内嵌的数组甚至是数据类型的嵌套。例如:
1
| dtype=[('x',np.int64,3),('y',np.int32)]
|
array([([0, 0, 0], 0), ([0, 0, 0], 0), ([0, 0, 0], 0), ([0, 0, 0], 0)],
dtype=[('x', '<i8', (3,)), ('y', '<i4')])
1
| dtype=[('x',[('a','f8'),('b','f4')]),('y',np.int32)]
|
1
| self_arr2=np.array([((1,2),5),((3,4),6)],dtype=dtype)
|
array([1., 3.])
随机方式
此外,NumPy也提供了一些生成随机元素的方式来创建ndarray,这些随机数可以满足不同的概率分布。下面为一些使用示例:
1
| np.random.permutation(test)
|
array([[ 3.8, 2.1, -5.4, 0. ],
[ 0.5, -0.3, 2.5, 2.8]])
1
| np.random.permutation(20)
|
array([15, 10, 14, 13, 1, 12, 11, 19, 8, 6, 16, 4, 2, 5, 17, 9, 7,
18, 3, 0])
array([[[0.3927848 , 0.83607876],
[0.33739616, 0.64817187]]])
1
| np.random.uniform(low=-2.0,high=4.0,size=(3,4))
|
array([[ 0.20944924, 3.74293095, -1.15789532, 3.22052355],
[ 0.84164827, 2.80546451, 1.12286488, 2.07327718],
[ 2.32379593, 1.49211875, 1.22423938, 2.55169375]])
array([[-0.06491034, -0.96898025, 0.59124281],
[-0.7827755 , -0.44423283, -0.34518616],
[-0.88180055, -0.44265324, -0.5409163 ]])
1
| np.random.normal(loc=-2.0,scale=2.0,size=(3,3))
|
array([[-4.64645474, -2.22559784, -0.18530811],
[-0.36946018, -1.5418041 , -4.05235756],
[-1.04494906, 0.58539646, -3.46291647]])
1
| np.random.randint(0,5,size=(3,4))
|
array([[3, 4, 1, 2],
[4, 3, 4, 4],
[4, 3, 4, 4]])
1
| np.random.binomial(10,0.3,size=(4,3))
|
array([[3, 3, 3],
[3, 2, 4],
[2, 4, 5],
[4, 0, 3]])
1
| np.random.beta(3,4,size=(2,2))
|
array([[0.30826832, 0.46266575],
[0.68918031, 0.67705037]])
1
| np.random.chisquare(2,size=(2,2))
|
array([[4.97116465, 5.08060897],
[0.17354098, 0.65068082]])
1
| np.random.gamma(3,scale=1.0,size=(2,2))
|
array([[4.6552704 , 3.43428893],
[1.11959827, 2.99619096]])
ndarray的内部构造
ndarray的数据结构
ndarray的内部包含如下内容:一个指向数据的指针,数据类型dtype,一个shape属性表示数组形状的tuple,一个表示stride(用于指示应进行维度转换的字节数)的tuple
数据类型的关系
数组的I/O操作
1 2
| np.save('test_array',test) np.savez('test_array2',a=test1,b=test2)
|
1 2 3
| arch1=np.load('test_array.npy') arch2=np.load('test_array2.npz') np.loadtxt('txtname.txt',delimiter='')
|
切片和索引操作
NumPy的ndarray也支持类似于list、tuple的切片和索引操作,但是稍有不同。具体表现为:
- 一个ndarray的切片或者索引是对原始array的引用,在对切片和索引得到的ndarray进行修改的时候会直接对原始的ndarray进行修改。如果要使得切片或索引部分是一个副本,则可以调用ndarray的
copy()
方法。
1
| test_slice1=np.array([0,1,2,3,4,5,6,7,8,9])
|
1 2 3
| arr_slice=test_slice1[5:8] arr_slice[1]=12345 test_slice1
|
array([ 0, 1, 2, 3, 4, 5, 12345, 7, 8,
9])
1 2
| arr_slice[:]=32 test_slice1
|
array([ 0, 1, 2, 3, 4, 32, 32, 32, 8, 9])
1 2
| test_slice1.put([5,6,7],33)
|
array([ 0, 1, 2, 3, 4, 33, 33, 33, 8, 9])
- 多维数组也可以做切片和索引操作。如果要对多个维度同时做切片操作,则需要在每一个维度的切片操作之间,用逗号把它们隔开。而对于多维数组的索引,规则比起多维数组的切片更加复杂,下面以具体的代码来进行说明。
1
| test_slice2=np.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, 30, 31]])
|
array([[12, 13],
[20, 21]])
array([[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15],
[18, 19],
[22, 23],
[26, 27],
[30, 31]])
array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13],
[16, 17],
[20, 21],
[24, 25],
[28, 29]])
array([4, 5])
array([[ 8, 9, 10, 11],
[28, 29, 30, 31]])
1
| test_slice2.take([2,-1],axis=0)
|
array([[ 8, 9, 10, 11],
[28, 29, 30, 31]])
7
注意下面三种不同的索引方式得到的结果也有很大差别:
1
| test_slice2[[2,-1],[0,1]]
|
array([ 8, 29])
1
| test_slice2[[2,-1]][[0,1]]
|
array([[ 8, 9, 10, 11],
[28, 29, 30, 31]])
1
| test_slice2[np.ix_([2,-1],[0,1])]
|
array([[ 8, 9],
[28, 29]])
- ndarray在索引时支持传入一个布尔类型的ndarray进行索引,只选出布尔值为真的位置上对应的那些值。
1
| test_slice2[test_slice2>5]
|
array([ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31])
1
| test_slice2[test_slice2[:,0]<10]
|
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
1
| np.where(np.array([True,False,False,True]),np.array([1.1,1.2,1.3,1.4]),np.array([2.1,2.2,2.3,2.4]))
|
array([1.1, 2.2, 2.3, 1.4])
ndarray的运算
ndarray的一元运算
ndarray的一元运算是对其中的每一个元素都进行运算操作。常用的操作如下:
1
| test=np.array([[0.5,-0.3,2.5,2.8],[3.8,2.1,-5.4,0.0]])
|
array([[ 0.5, -0.3, 2.5, 2.8],
[ 3.8, 2.1, -5.4, 0. ]])
array([[0.5, 0.3, 2.5, 2.8],
[3.8, 2.1, 5.4, 0. ]])
array([[0.70710678, nan, 1.58113883, 1.67332005],
[1.94935887, 1.44913767, nan, 0. ]])
array([[ 0.25, 0.09, 6.25, 7.84],
[14.44, 4.41, 29.16, 0. ]])
array([[1.64872127e+00, 7.40818221e-01, 1.21824940e+01, 1.64446468e+01],
[4.47011845e+01, 8.16616991e+00, 4.51658094e-03, 1.00000000e+00]])
array([[-0.69314718, nan, 0.91629073, 1.02961942],
[ 1.33500107, 0.74193734, nan, -inf]])
array([[ 1., -1., 1., 1.],
[ 1., 1., -1., 0.]])
array([[ 1., -0., 3., 3.],
[ 4., 3., -5., 0.]])
array([[ 0., -1., 2., 2.],
[ 3., 2., -6., 0.]])
array([[ 0., -0., 2., 3.],
[ 4., 2., -5., 0.]])
(array([[ 0.5, -0.3, 0.5, 0.8],
[ 0.8, 0.1, -0.4, 0. ]]),
array([[ 0., -0., 2., 2.],
[ 3., 2., -5., 0.]]))
array([[False, True, False, False],
[False, False, True, False]])
array([[False, False, False, False],
[False, False, False, False]])
array([[ 0.87758256, 0.95533649, -0.80114362, -0.94222234],
[-0.79096771, -0.5048461 , 0.63469288, 1. ]])
array([[1.04719755, 1.87548898, nan, nan],
[ nan, nan, nan, 1.57079633]])
array([[False, False, False, False],
[False, False, False, True]])
ndarray的二元运算
对于ndarray的二元运算,它是对两个ndarray相对应位置上的元素分别进行计算,输出结果是一个形状相同的二维数组。如果它们形状不同,则首先判断能否对ndarray做broadcast使之变为形状相同。如果可以则按照broadcast之后的ndarray计算,反之则报错。broadcast操作将在下面进行详细描述。
因此,如果是一个ndarray与一个标量进行计算,则相当于自动把标量做broadcast使之与ndarray具有相同的形状,然后再进行计算。
下面是一些常用的二元操作:
1 2
| test1=np.array([[1,2,3,4],[5,6,7,8]]) test2=np.array([[3,4,5,6],[7,8,9,0]])
|
array([[ 4, 6, 8, 10],
[12, 14, 16, 8]])
array([[-2, -2, -2, -2],
[-2, -2, -2, 8]])
array([[ 3, 8, 15, 24],
[35, 48, 63, 0]])
array([[0.33333333, 0.5 , 0.6 , 0.66666667],
[0.71428571, 0.75 , 0.77777778, inf]])
array([[0, 0, 0, 0],
[0, 0, 0, 0]], dtype=int32)
array([[ 1, 16, 243, 4096],
[ 78125, 1679616, 40353607, 1]], dtype=int32)
array([[1, 2, 3, 4],
[5, 6, 7, 0]], dtype=int32)
array([[3, 4, 5, 6],
[7, 8, 9, 8]])
array([[False, False, False, False],
[False, False, False, True]])
1 2 3
| np.logical_and(test1,test2)
|
array([[ True, True, True, True],
[ True, True, True, False]])
1
| np.copysign(np.array([-2,2,-2,2]),np.array([1,-1,-1,1]))
|
array([ 2., -2., -2., 2.])
ndarray的统计运算
ndarray支持一些类型的统计运算,例如:
1
| test3=np.array([[0.3,1.5,-0.5,2.4],[3.3,-5.5,8.1,-2.8]])
|
6.8
array([3.7, 3.1])
0.85
3.826878623630491
14.645000000000001
-5.5
5
array([ 0.3 , 0.45 , -0.225 , -0.54 , -1.782 ,
9.801 , 79.3881 , -222.28668])
array([[ 0.3, 1.5, -0.5, 2.4],
[ 3.6, -4. , 7.6, -0.4]])
对于布尔类型的ndarray有如下这些特殊的统计运算操作:
1
| test_bool=np.array([False,True,True,False,False,True,False])
|
3
True
False
备注:在NumPy的一些函数中,如果传入axis=……
参数,则代表这一函数操作在这个传入的维度上面进行。假设有一个三维的array,它的元素可以用\(a_{ijk}\)来表示,当我们在np.sum()
函数中传入axis=1
,那么最终得到的结果便可以用数学公式表示为\(\sum_{j=1}^{n}a_{ijk}\),也就是说这个操作是在维度\(j\)上进行的。
聚合运算
NumPy中的一些函数支持进一步的聚合操作,支持聚合操作的函数包括add
、multiply
、subtract
、logical_and
等。
reduce
函数是对某个维度上的数据做连续的累计操作,最终得到的ndarray相比于传入的ndarray维度减1。例如:
1
| np.multiply.reduce(test3,axis=1)
|
array([ -0.54 , 411.642])
reduceat
函数与reduce
函数类似,但是需要额外传入一个list,用于确定参与聚合计算的范围。例如:
1
| np.subtract.reduceat(test3,[0,2,3],axis=1)
|
array([[-1.2, -0.5, 2.4],
[ 8.8, 8.1, -2.8]])
accumulate
函数与reduce
函数类似,但是会保留在这个维度上进行计算时的中间结果,例如:
1
| np.add.accumulate(test3,axis=1)
|
array([[ 0.3, 1.8, 1.3, 3.7],
[ 3.3, -2.2, 5.9, 3.1]])
outer
函数传入两个ndarray,代表第一个与第二个ndarray中所有的元素可以组成的元素对进行计算。假设传入的两个ndarray为x和y,那么outer
函数生成的ndarray的规模为(x.shape,y.shape)。例如:
1
| np.add.outer(test1,test2)
|
array([[[[ 4, 5, 6, 7],
[ 8, 9, 10, 1]],
[[ 5, 6, 7, 8],
[ 9, 10, 11, 2]],
[[ 6, 7, 8, 9],
[10, 11, 12, 3]],
[[ 7, 8, 9, 10],
[11, 12, 13, 4]]],
[[[ 8, 9, 10, 11],
[12, 13, 14, 5]],
[[ 9, 10, 11, 12],
[13, 14, 15, 6]],
[[10, 11, 12, 13],
[14, 15, 16, 7]],
[[11, 12, 13, 14],
[15, 16, 17, 8]]]])
数组的线性代数运算
NumPy提供了一些线性代数运算。需要注意的是,本节中的一些操作可以对大于二维的array进行计算,如果要这样使用需要注意维度大小上的要求,并清楚运算的数学含义。
1 2 3
| test_linalg1=np.random.rand(3,4) test_linalg2=np.random.rand(4,3) test_linalg3=np.random.rand(4,4)
|
array([[0.67166004, 0.67521641, 0.92385308, 0.17172312],
[0.08287326, 0.91389572, 0.50537867, 0.44940627],
[0.49319114, 0.24830729, 0.7845657 , 0.0541078 ]])
array([[0.39854758, 0.88405379, 0.46193288],
[0.17077872, 0.48180729, 0.4009363 ],
[0.21988187, 0.74787762, 0.12843288],
[0.87389188, 0.35833092, 0.58089653]])
array([[0.91681047, 0.0559406 , 0.90109644, 0.85956406],
[0.5495678 , 0.01228935, 0.40510975, 0.00860076],
[0.63290332, 0.88460151, 0.58796459, 0.25524597],
[0.0586652 , 0.16806904, 0.28365241, 0.29483814]])
1
| np.dot(test_linalg1,test_linalg2)
|
array([[0.73620706, 1.67157054, 0.7993871 ],
[0.69295897, 1.0525836 , 0.73066163],
[0.45876187, 1.16179138, 0.45957167]])
在NumPy中还有一个功能与np.dot
相似的函数:np.matmul
。当array为二维时,它与np.dot
的计算结果相同。但是在多维的情况下,matmul
会将array看作是多个二维数组的堆叠,在计算时取两个array的最后两个维度,按照矩阵乘法的规则来计算。而dot
则是按照如下规则来计算:dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])。
例如一个array的维度为(9,5,7,4),另一个为(9,5,4,3),那么使用matmul
得到的结果是维度为(9,5,7,3)的数组,而使用dot
得到的则是(9,5,7,9,5,3)。
1
| test_linalg1.dot(test_linalg2)
|
array([[0.73620706, 1.67157054, 0.7993871 ],
[0.69295897, 1.0525836 , 0.73066163],
[0.45876187, 1.16179138, 0.45957167]])
array([[0.67166004, 0.08287326, 0.49319114],
[0.67521641, 0.91389572, 0.24830729],
[0.92385308, 0.50537867, 0.7845657 ],
[0.17172312, 0.44940627, 0.0541078 ]])
1 2
| test_transpose=np.random.rand(2,5,4,3) np.shape(test_transpose.T)
|
(3, 4, 5, 2)
1
| np.linalg.inv(test_linalg3)
|
array([[ 1.41156052, -0.98749103, 0.83882032, -4.81260336],
[-0.21076796, -1.03011343, 1.23951372, -0.42854889],
[-1.94482628, 3.90240586, -1.18111701, 6.57857386],
[ 1.71032402, -2.97066486, 0.26283316, -1.73542744]])
1
| np.linalg.pinv(test_linalg2)
|
array([[-0.46907312, -1.92370125, 1.09489796, 1.45867813],
[ 0.48237103, -0.25944216, 1.15432715, -0.45973217],
[ 0.54234896, 2.95669978, -2.44534867, -0.20987198]])
array([0.39854758, 0.48180729, 0.12843288])
1
| np.diag(np.diag(test_linalg3))
|
array([[0.91681047, 0. , 0. , 0. ],
[0. , 0.01228935, 0. , 0. ],
[0. , 0. , 0.58796459, 0. ],
[0. , 0. , 0. , 0.29483814]])
1.0087877438514739
1
| np.linalg.det(test_linalg3)
|
-0.060734760345177434
1
| np.linalg.qr(test_linalg2)
|
(array([[-0.39853949, -0.55826311, 0.1397547 ],
[-0.17077525, -0.34967478, 0.76189453],
[-0.2198774 , -0.58700406, -0.63012748],
[-0.87387414, 0.4706337 , -0.05408067]]),
array([[-1.0000203 , -0.91218862, -0.78843843],
[ 0. , -0.93237507, -0.20007854],
[ 0. , 0. , 0.2576841 ]]))
1
| np.linalg.svd(test_linalg2)
|
(array([[-0.6124607 , 0.31110915, 0.13463208, -0.71412688],
[-0.36061856, 0.14909045, 0.76134499, 0.51776452],
[-0.4109163 , 0.50488233, -0.60516287, 0.45827887],
[-0.57095879, -0.79125025, -0.18975224, 0.10919333]]),
array([1.72222085, 0.64558318, 0.21609566]),
array([[-0.51967203, -0.71251265, -0.4714517 ],
[-0.66761255, 0.68299619, -0.29632698],
[-0.53313644, -0.16075423, 0.83061641]]))
1
| test_linalg4=np.random.rand(4,1)
|
1
| np.linalg.lstsq(test_linalg3,test_linalg4)
|
(array([[-0.85081594],
[ 0.23595236],
[ 2.3445102 ],
[-0.76479464]]),
array([], dtype=float64),
4,
array([1.97814445, 0.75043168, 0.40950042, 0.09991112]))
1
| np.linalg.norm(test_linalg2,ord=2,axis=1)
|
array([1.07413838, 0.64965648, 0.79004049, 1.10884122])
对于numpy中的ndarray类,如果要对其做线性代数运算,需要写成上面那些函数调用的形式,比较麻烦。为了便于对一个矩阵做线性代数运算,我们可以将一个ndarray转换为一个matrix类。这样,就可以像matlab一样,直接使用运算符。例:
1 2
| X1=np.matrix(test_linalg1) X2=np.matrix(test_linalg2)
|
matrix([[0.73620706, 1.67157054, 0.7993871 ],
[0.69295897, 1.0525836 , 0.73066163],
[0.45876187, 1.16179138, 0.45957167]])
自定义函数
NumPy可以将一个自定义函数从标量运算转变为支持numpy数组运算的函数,从而使得ndarray可以作为函数的参数。
1 2
| def add_elements(x,y): return x+y
|
1
| add_them=np.frompyfunc(add_elements,2,1)
|
1
| add_them=np.vectorize(add_elements)
|
1
| add_them(np.arange(4),np.arange(4))
|
array([0, 2, 4, 6], dtype=object)
排序与筛选操作
排序
numpy中的排序函数可以对元素进行排序。同时,这些排序函数支持三种类型的排序:quicksort、mergesort、heapsort,可以使用kind参数传入排序函数内。
1 2
| test_sort1=np.array([2,3,4,1,4,2,5,8,3]) test_sort2=np.array([6,3,7,3,5,2,6,2,7,1])
|
1
| test_sort2.sort(kind='mergesort')
|
array([1, 2, 2, 3, 3, 5, 6, 6, 7, 7])
array([1, 2, 2, 3, 3, 4, 4, 5, 8])
1
| test_sort1.argsort(kind='quicksort')
|
array([3, 0, 5, 1, 8, 2, 4, 6, 7], dtype=int64)
numpy中的searchsorted函数可以在已经排序好的array中做二分查找,返回一个表示位置的整数,被查找元素插入到这个位置上时不会影响到array中的元素排序。
如果有相同元素,在返回位置时会默认返回最左端那个元素的位置。也可以传入参数使其返回右端元素的位置。例:
1
| test_sort2.searchsorted([2,3])
|
array([1, 3], dtype=int64)
1
| test_sort2.searchsorted([2,3],side='right')
|
array([3, 5], dtype=int64)
筛选操作
array([1, 2, 3, 4, 5, 8])
1
| np.intersect1d(test_sort1,test_sort2)
|
array([1, 2, 3, 5])
1
| np.union1d(test_sort1,test_sort2)
|
array([1, 2, 3, 4, 5, 6, 7, 8])
1
| np.in1d(test_sort1,test_sort2)
|
array([ True, True, False, True, False, True, True, False, True])
1
| np.setdiff1d(test_sort1,test_sort2)
|
array([4, 8])
1
| np.setxor1d(test_sort1,test_sort2)
|
array([4, 6, 7, 8])
ndarray的形状改变
1
| test_shape=np.arange(20)
|
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
1 2
| test_shape.reshape((2,2,5))
|
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
1
| test_shape.reshape(5,-1)
|
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
1 2
| test_shape2=test_shape.reshape((2,2,5)) test_shape2.transpose((2,0,1))
|
array([[[ 0, 5],
[10, 15]],
[[ 1, 6],
[11, 16]],
[[ 2, 7],
[12, 17]],
[[ 3, 8],
[13, 18]],
[[ 4, 9],
[14, 19]]])
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
1
| test_shape2.flatten('C')
|
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
array([ 0, 10, 5, 15, 1, 11, 6, 16, 2, 12, 7, 17, 3, 13, 8, 18, 4,
14, 9, 19])
数组的合并与分离
数组的合并
将两个数组合并,可以使用下面这些操作:
1
| np.concatenate([test_shape2,test_shape2],axis=2)
|
array([[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14, 10, 11, 12, 13, 14],
[15, 16, 17, 18, 19, 15, 16, 17, 18, 19]]])
1
| np.vstack((test_shape2,test_shape2))
|
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
1
| np.hstack([test_shape2,test_shape2])
|
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
1
| np.dstack([test_shape2,test_shape2])
|
array([[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14, 10, 11, 12, 13, 14],
[15, 16, 17, 18, 19, 15, 16, 17, 18, 19]]])
数组的复制
下面这些函数可以将数组中的元素复制一定的次数,从而形成一个更大的数组:
1 2
| test_shape2.repeat([2,3],axis=1)
|
array([[[ 0, 1, 2, 3, 4],
[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[ 5, 6, 7, 8, 9],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[15, 16, 17, 18, 19],
[15, 16, 17, 18, 19]]])
1
| np.tile(test_shape2,(2,1,2))
|
array([[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14, 10, 11, 12, 13, 14],
[15, 16, 17, 18, 19, 15, 16, 17, 18, 19]],
[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9, 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14, 10, 11, 12, 13, 14],
[15, 16, 17, 18, 19, 15, 16, 17, 18, 19]]])
数组的分割
下面的函数可以将一个ndarray分成多个:
1 2
| np.split(test_shape2,[0,2],axis=2)
|
[array([], shape=(2, 2, 0), dtype=int32),
array([[[ 0, 1],
[ 5, 6]],
[[10, 11],
[15, 16]]]),
array([[[ 2, 3, 4],
[ 7, 8, 9]],
[[12, 13, 14],
[17, 18, 19]]])]
1
| np.hsplit(test_shape2,[1])
|
[array([[[ 0, 1, 2, 3, 4]],
[[10, 11, 12, 13, 14]]]),
array([[[ 5, 6, 7, 8, 9]],
[[15, 16, 17, 18, 19]]])]
1
| np.vsplit(test_shape2,[1])
|
[array([[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]]]),
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])]
1
| np.dsplit(test_shape2,[2])
|
[array([[[ 0, 1],
[ 5, 6]],
[[10, 11],
[15, 16]]]),
array([[[ 2, 3, 4],
[ 7, 8, 9]],
[[12, 13, 14],
[17, 18, 19]]])]
Broadcast操作
前面已经提到,在对两个形状不同的数/数组进行运算操作的时候,可能会对数字或者数组做一些扩展操作。
只有当两个array相容时才能做数据扩展,即它们每个维度上的长度按照从右往左的顺序进行比较时,要么在某个维度上二者维度相等,要么某个维度上其中一个array的长度为1(如果缺失则可以看作为1)。如果两个array相容,会在长度为1的维度上通过复制元素将array扩展至与另一个array长度相同。
下面为一些broadcast操作的图例:
可以在slide操作中结合np.newaxis,手动添加一个新的维度,例如:
1
| test_shape2[:,np.newaxis,:,:]
|
array([[[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]]]
[[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]]])
参考
- Python for Data Analysis, 2nd Edition.