亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Python常用模塊之numpy

標簽:
Python

numpy

在讨论numpy的具体函数和方法之前,我要先说明一下两个问题:1,numpy中的数组和向量。2,numpy中的“多轴数组”。

维度vs轴数

numpy中里有多维数组,为了避免和线性代数中的多维数组区别开,这里暂时称之为多轴数组。

我们首先生成一个三维数组,里面存放数字0-36:

arr = np.arange(36).reshape(3, 4, 3)

我们可以将这个三轴数组看作一个立方体:每一个小立方体代表一个数字,这些数字按照一定的方式堆砌(排列组合)成一个3*4*3的立方体。三个轴分别为axis0, axis1, axis2。

那么这个reshape方法中的3个参数3,4,3到底指的是什么呢?其实,它们规定了:这个轴的方向上有几个维度!

注意,我们说的numpy中的二维数组(比如是n阶的),实际上是线性代数中的n维数组,或者称为n阶方阵。我们在python里把它叫做二维数组,并不表明这个数组在线性空间中是2阶的,而是这个数组可以在二维平面中表示出来。比如我们举的这个例子,三轴数组就不能在二维平面中表现出来,但我们可以在三维空间里将它形象化。

有了上面的解释,我们便可以知道:axis0方向上有三个维度,axis1方向上有4个维度,axis2方向上有3个维度。

从axis0的方向上看过去,一共有3个维度,每一维都是4*3的”二轴数组“。

从axis1的方向上看过去,一共有4个维度,每一维都是3*3的”二轴数组“。

从axis2的方向上看过去,一共有3个维度,每一维都是3*4的”二轴数组“。

好了,其实我们只要知道python中的多维数组,和线性代数中的多维数组完全不同就可以了。我们通常还是只使用二轴数组,只要不造成歧义,表述成“二维n阶数组”也是可以的。

numpy中按轴进行的操作有很多,我们将轴的概念理解好,会对矩阵操作带来很大的方便,接下来举几个例子:

import numpy as nparr = np.arange(12).reshape(4, 3)mean0 = np.mean(arr,axis=0) #在axis0方向(向下,列方向)上操作,即对每一列求均值mean1 = np.mean(arr,axis=1) #每一行的均值sum0 = np.sum(arr,axis=0)   #每一列的和sum1 = np.sum(arr,axis=1)   #每一行的和min0 = arr.min(0)   #每一列的最小值min1 = arr.min(1)   #每一行的最小值max0 = arr.max(0)   #每一列的最大值min1 = arr.max(1)   #每一行的最大值mean0Out[8]: array([4.5, 5.5, 6.5])mean1Out[9]: array([ 1.,  4.,  7., 10.])sum0Out[12]: array([18, 22, 26])sum1Out[11]: array([ 3, 12, 21, 30])

我们定义了一个4*3的矩阵。axis0方向的长度是4,axis1方向的长度是3.从axis0的方向看过去矩阵是3个4维列向量,从axis1的方向看过去是4个3维的行向量。

所以,按axis=0操作时,都是按照(axis1个)列向量操作的;按axis=1操作时都是按照(axis0个)列向量操作的;

我们按照axis0来求每个列向量平均数,得到了一个3阶数组;按照axis1来求每个行向量平均数,得到了一个4阶数组。

我们已经将arr reshape成了一个4*3的矩阵,axis0对应的轴上应该有四个维度(4行),按axis0轴求和就是将这四个维度(中的4个数据)求和,之后再按axis1的方向移动求另外三个数据的和,一共移动3次。

当然也可以简记为:axis=0是按列,axis=1是按行操作。

向量vs数组

我们用shape方法来获取一个矩阵的形状,它会会返回一个元组,还会用到T方法来进行矩阵转置。举一个简单的例子:

arr1 = np.arange(36)arr1.shapeOut[14]: (36,)arr1.T.shapeOut[15]: (36,)

对于arr1这个数组,转置没有效果。这说明我们有一个错误的观念:多维数组就是矩阵,一维数组就是列向量。这句话的前半句没有任何问题,但一维数组只是“一组有顺序的数”,并不是向量。你瞧它的形状是(36,),而非(36,1)。欲将其变为列向量或者行向量也简单,需要用到numpy中的expand_dims方法,需要给他两个参数,第二个是给定的轴(在这个轴的方向上增加维度)。也可以直接用matrix生成矩阵。

arr2 = np.expand_dims(arr1, axis=0) #朝着axis0的方向,即行arr3 = np.expand_dims(arr1, axis=1) #朝着axis1的方向,即列arr4 = np.matrix([1, 2, 3])arr5 = np.matrix([1, 2, 3]).Tarr2.shapeOut[17]: (1, 36)    #行向量arr3.shapeOut[18]: (36, 1)    #列向量arr4.shapeOut[19]: (1, 3)     #行向量arr5.shapeOut[20]: (3, 1)     #列向量

除了expand_dims方法外,还有其他的构造向量的方法,我们用下面的例子做一个测试,探索一下array函数构造矩阵的原理:

test1 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])test2 = np.array([[0, 1, 2, 3, 4, 5, 6, 7, 8]])test1.shapeOut[25]: (9,)test2.shapeOut[26]: (1, 9)

可以看出test1的方式是构造了一个数组,而test2的方式是构造了一个行向量。分析一下array构造矩阵的原理:

np.array([[#, #, #],        [#, #, #],        [#, #, #]])

array方法中,传入的参数是一个列表。这个列表中存在n个子列表,便构造n行的矩阵,每个子列表中有m列元素就构造m列的矩阵。所以array的维度是由传入的列表中,子列表的个数n,和子列表中的元素个数m共同确定的。

那么特例就是:子列表的个数为1,相当于构造了一个1行的矩阵,即行向量。子列表有多个,但每个子列表中元素个数为1,那么这就是一个列向量咯。

数乘vs点乘

arr1 = np.array([[1, 2, 3],                 [4, 5, 6],                 [7, 8, 9]])arr2 = np.arange(1, 10).reshape((3, 3))arr3 = np.eye(3)arr4 = np.matrix([1,2,3]).Tarr1 + 10Out[65]:[[11 12 13] [14 15 16] [17 18 19]]arr1 + arr4Out[77]: matrix([[ 2,  3,  4],        [ 6,  7,  8],        [10, 11, 12]]) arr1*arr3Out[66]:[[1. 0. 0.] [0. 5. 0.] [0. 0. 9.]] arr1.dot(arr3)  #等同于np.dot(arr1,arr3)Out[67]:[[1. 2. 3.] [4. 5. 6.] [7. 8. 9.]] 2**arr1Out[68]:[[  2   4   8] [ 16  32  64] [128 256 512]] arr1**2Out[69]:[[ 1  4  9] [16 25 36] [49 64 81]]

数与矩阵相加,即与矩阵每一个元素相加。列向量与矩阵相加,即列向量与每一列相加。

np.dot(arr1,arr3)进行的是常规的矩阵乘法,两个矩阵的形状必须遵循“前列等后行“的规则。而arr1*arr3就是对应位置的元素作乘积,需要两个矩阵的形状相同。

切片vs拷贝

我们之间已经知道列表的切片就等于浅拷贝。那么对于数组也一样吗。

myarr16 = myarr[1]myarr17 = myarr[1, 2]myarr18 = myarr[1][2]myarr19 = myarr[:, ::-1]myarr20 = myarr[::-1, ::-1] myarr21 = myarr[::-1].copy()np.may_share_memory(myarr19, myarr)Out[46]: Truenp.may_share_memory(myarr20, myarr)Out[47]: Truenp.may_share_memory(myarr21, myarr)Out[48]: False

数组的切片有两种方法,如myarr17和myarr18。为了和列表切片区分开来,习惯于用myarr18的构造方式。

用numpy中的方法may_share_memory来查看,两个数组是否共享内存,也即是否为新数组创了新内存。可以发现切片始终与原数组共享内存,而copy方法进行了内存的创建,赋值。

高级切片

array的切片的元素可以是一个列表,表示抽取除这些行,或列。

myarr22 = np.random.randint(0, 20 ,10).reshape(2, 5)myarr23 = myarr22[:, [4, 2]] myarr23Out[54]: array([[17,  4],       [ 1, 15]])

myarr22是一个2*5的矩阵,我们得到的myarr23是抽取出每一行的第5列,和第3列组成的新数组。

重新排序

myarr19 = myarr[:, ::-1]myarr20 = myarr[::-1, ::-1] myarr21 = myarr[::-1].copy()

其实我们利用切片就可以对数组进行逆序排列。

myarr19进行列逆序排列, 第一个:不能少。因为np是默认按行进行操作的,如果只给一个参数,如myarr21会将该切片操作应用到每一行上,即将myarr的行之间逆序。

数组没有列表的原地排序的sort方法。

array0 = np.array([[9, 8, 7, 6],                [6, 5, 4, 3],                [3, 2, 1, 0]])array1 = np.sort(array0, axis=0)    #朝着axis0的维度,对每一个列向量排序array2 = np.argsort(array0, axis=0)array3 = np.sort(array0, axis=1)    #朝着axis1的维度,对每一个行向量排序array4 = np.argsort(array0, axis=1) array1Out[50]: array([[3, 2, 1, 0],       [6, 5, 4, 3],       [9, 8, 7, 6]])array2Out[51]: array([[2, 2, 2, 2],       [1, 1, 1, 1],       [0, 0, 0, 0]], dtype=int64)array3Out[52]: array([[6, 7, 8, 9],       [3, 4, 5, 6],       [0, 1, 2, 3]])array4Out[53]: array([[3, 2, 1, 0],       [3, 2, 1, 0],       [3, 2, 1, 0]], dtype=int64)

array2是按列排序返回顺序列表,返回矩阵中的列向量表示:原矩阵中对应列向量从小到大排列之后,对应元素在原列表中的位置。也即是array1中列向量的元素在array0中对应列向量的索引。

array4是按行排序返回顺序列表,返回矩阵中的行向量表示:原矩阵中对应行向量从小到大排列之后,对应元素在原列表中的位置。也即是array3中列向量的元素在array0中对应行向量的索引。

等差数列

等差数列有两种生成方法:

myarr3 = np.arange(1, 10, 3)myarr4 = np.linspace(9, 10, 5)myarr5 = np.linspace(9, 10, 5, endpoint = False)myarr3Out[41]: array([1, 4, 7])myarr4Out[42]: array([9. , 9.25, 9.5, 9.75, 10.])myarr5Out[43]: array([9. , 9.2, 9.4, 9.6, 9.8])

arange(start, end(exclusive), step) 三个参数,前两个参数表示生成等差数列的区间,左闭右开。第三个参数为步长缺省值为1。

linspace(start, end, number_point) 将区间切分为number_point-1份。其实linspace还有一个默认参数 endpoint = True,缺省时置True,即左闭右闭的闭区间。np.linspace(start, end, number_point, endpoint = False)  将区间切分为number_point份,因为endpoint = False,所以与arange一样是左闭右开。

特殊矩阵

全零矩阵,全一矩阵,单位阵,对角阵,随机矩阵的创建方法:

myarr6 = np.ones((3, 4))myarr7 = np.zeros((3, 4))myarr8 = np.eye(4)  #eye的参数不能是远足,只能是一个数字myarr9 = np.diag([1, 2, 3, 4])myarr10 = np.random.rand(4, 2)

其中,ones和zeros的参数都只能是来描述矩阵的形状的元组。eye的参数只能是一个int类型数据。diag的参数一个存放着特征值的列表。

另外提一个空矩阵,只分配地址,但不存入数据

矩阵扩展

我们可以用numpy中的tile函数对数组朝指定方向进行扩展指定次数:

mylist = [7, 999, 4]array1 = np.tile(mylist, (1, 3))array2 = np.tile(mylist, (3, 2))array3 = np.tile(mylist, 2)array1Out[55]: array([[  7, 999,   4,   7, 999,   4,   7, 999,   4]])array2Out[56]: array([[  7, 999,   4,   7, 999,   4],       [  7, 999,   4,   7, 999,   4],       [  7, 999,   4,   7, 999,   4]])array3Out[57]: array([  7, 999,   4,   7, 999,   4])

tile(mylist, (m, n))相当于构造了一个m*n的矩阵,并将里面的每个元素填充维mylist。

hstack函数,和r_函数都是在axis0方向上合并,即合并在右边。vstack函数,和c_函数都是在axis1方向上合并,即合并在下边。

myarr1 = np.array([[ 8.,  5.],                [ 1.,  6.]])myarr2 = np.array([[ 1.,  9.],                [ 8.,  5.]])np.hstack((myarr1, myarr2))Out[69]: array([[8., 5., 1., 9.],       [1., 6., 8., 5.]])np.c_[myarr1, myarr2]Out[73]: array([[8., 5., 1., 9.],       [1., 6., 8., 5.]])       np.vstack((myarr1, myarr2))array([[8., 5.],       [1., 6.],       [1., 9.],       [8., 5.]])       np.r_[myarr1, myarr2]Out[72]: array([[8., 5.],       [1., 6.],       [1., 9.],       [8., 5.]])

数据类型

myarr12 = np.array([1, 2, 3])myarr13 = np.array([1, 2, 3, 4], dtype = 'float')myarr14 = np.array([1., 2., 3.])myarr15 = np.array([1+1j, 2+2j, 3+3*1j])    #numpy中的复数符号是1j,而不是j

myarr12是int32型的数组,myarr13,myarr14都是float64型的数组。我们当然也可以构造复数complex128类型的数组,比如myarr15。

矩阵大小

arr0 = np.arange(0, 12).reshape(4, 3)arr0.sizeOut[65]: 12arr0.shapeOut[66]: (4, 3)arr0.shape[0]Out[67]: 4arr0.shape[1]Out[68]: 3arr0.dtype.itemsizeOut[69]: 4

生成一个4*3的矩阵,size方法获得其中元素的个数,返回一个int数据。shape方法返回一个元组(num,dim),第一个元素为行数,第二个元素为列数。

dtype.itemsize是numpy中的方法,获取数组所占用的字节数。

原文出处

點擊查看更多內容
1人點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消