博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python机器学习、深度学习:快速、完全的Numpy入门指南
阅读量:5925 次
发布时间:2019-06-19

本文共 13784 字,大约阅读时间需要 45 分钟。

NumPy是python的第三方科学计算包,全名称为Numerical Python extensions。NumPy包含以下几个功能组件:强大的N维数组对象(可以操控多为数组),优美巧妙的功能(广播)函数,对于线性代数,傅里叶变换,随机数的生成有着很好的支持。现在广泛用于机器学习与深度学习之中。

基础类型

NumPy中最基本的对象就是均匀多维数组,包含一系列相同类型的变量(一般数字),类似于数组,可以通过正整数来进行访问。注意,在Numpy中维数(dimensions)称之为axes。axes的数量就是rank(秩)。

举个例子,在一个三维空间中的一个点的坐标为[1, 3, 2],这是一个秩为1的数组,因为它只含有一个轴(axis),轴的长度为3。

接下来的这个例子的rank为2,因为它有两维。

(注意这里的维数于向量中的维数不同,这里的维数相当于C语言中数组的维数,又称轴数。另外这里的rank不等同于矩阵中的秩,在python的语言中,维数的数量称之为rank)

[[1, 0, 2], [0, 2, 1]]

第一维(轴)的数量为2([1, 0, 2],[0 ,2, 1]),第二维的数量为3(如第一个数组中的1,0,2)。

再来区别一下python中rank与矩阵中rank(秩)的区别,numpy中多维数组其实就是矩阵,拥有和矩阵一样的性质。以下讲解中数组一般为多维数组。

>>> a =np.array([[1,2,3],[2,3,4],[3,4,5]])  #这里定义了一个三行三列的多维数组(可以理解为矩阵)>>> aarray([[1, 2, 3],       [2, 3, 4],       [3, 4, 5]])>>> a.ndim  #在numpy中ndarry.ndim返回这个数组的rank,要注意,这里的rank是2,但是在矩阵中rank应该为32

注意NumPy中的数组类称之为ndarray,一般我们叫它的别名array,其这个与python标准库中的array.array不同,python中的只可以处理一维数组,功能上差很多。

基本定义方法

>>> import numpy as np>>> a = np.array([1,2,3])  #定义一个一维数组>>> a.size                 #输出a的容量 3>>> a.shape                #a的形状,对于单个一维数组来说 维数就是元素长度(3,)        >>> b = np.array([[1,2,3],[2,3,4],[3,4,5]])    #定义一个二维数组>>> b.size                 #b的容量为元素的数量 9        >>> b.shape                #b的形状,这里b是一个拥有三个数组,每个数组有三个元素(3, 3)        >>> b.shape[0]             #b中第一维的数量3        >>> b.shape[1]             #b重第二维的数量(即元素长度)3        >>> c = np.arange(15).reshape(3, 5)   #定义一个范围从数量为15,第一维为3,第二维为5的数组>>> carray([[ 0,  1,  2,  3,  4],       [ 5,  6,  7,  8,  9],       [10, 11, 12, 13, 14]])>>> c.shape                        #同上(3, 5)>>> c.ndim                         #数组的秩2>>> c.dtype.name                   #数组中元素的类型'int64'>>> c.itemsize                     #数组中元素字节数(大小) 这里的8为(64/8)8>>> c.size                         #C中元素数量15>>> type(c)                        #类型
>>> d = np.array([6, 7, 8])>>> darray([6, 7, 8])>>> type(d)

在平常的使用中,我们通常使用np做numpy的别名,这样可以使程序更加简洁便于阅读。

下面例子也中展示了array的基本构造,注意,这样初始化是错误的!

>>> a = np.array(1,2,3)    # 错的!>>> a = np.array([1,2,3])  # 应该这样

另外,还可以这样构造

>>> a = np.array([[1,2],[3,4]], dtype=complex)  #在后面通过函数参数指定类型>>> aarray([[ 1.+0.j,  2.+0.j],       [ 3.+0.j,  4.+0.j]])>>> b = np.zeros((3,3))             #构造全为0,(3,3)的数组>>> barray([[ 0.,  0.,  0.],       [ 0.,  0.,  0.],       [ 0.,  0.,  0.]])>>> d = np.zeros((2,3,4), dtype=np.int16)   #指定构造维数和元素类型>>> darray([[[0, 0, 0, 0],        [0, 0, 0, 0],        [0, 0, 0, 0]],       [[0, 0, 0, 0],        [0, 0, 0, 0],        [0, 0, 0, 0]]], dtype=int16)>>> a = np.ones((3,4))                #单位数组>>> aarray([[ 1.,  1.,  1.,  1.],       [ 1.,  1.,  1.,  1.],       [ 1.,  1.,  1.,  1.]])>>> e = np.arange(1, 10 ,2)           #定义范围为1-10,间隔为2的数组>>> earray([1, 3, 5, 7, 9])>>> f = np.arange(0, 2, 0.1)          #也支持浮点型>>> farray([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ,        1.1,  1.2,  1.3,  1.4,  1.5,  1.6,  1.7,  1.8,  1.9])>>> g = np.linspace(0,10,11)          #定义0-10中,均匀取11个点的数组>>> garray([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.])

基本操作

算术算法操作同样适合数组,numpy可以方便地在数组中进行操作。

>>> import numpy as np>>> a = np.array([1,2,3])   >>> b = np.arange(3)>>> barray([0, 1, 2])>>> c = a - b                     #对应元素相减>>> carray([1, 1, 1])>>> b**2                          #b中所有元素平方array([0, 1, 4], dtype=int32)>>> 10*np.sin(a)                  #a中所有元素通过sin函数乘于10array([ 8.41470985,  9.09297427,  1.41120008])>>> a < 2                         #判断a中的元素,返回bool类型array([ True, False, False], dtype=bool)

注意,numpy中的乘法符号*对数组中的每个元素也是同样起作用的,这个与矩阵中的乘法不同(dot)

>>> A = np.array( [[1,1],...             [0,1]] )>>> B = np.array( [[2,0],...             [3,4]] )>>> A*B                         # 对应元素乘积array([[2, 0],       [0, 4]])>>> A.dot(B)                    # 矩阵乘法array([[5, 4],       [3, 4]])>>> np.dot(A, B)                # 矩阵乘法array([[5, 4],       [3, 4]])

numpy中也支持+=-+运算,在原先存在的array中进行操作(不是新创建一个数组)。

>>> import numpy as np>>> a = np.array([[1,2,3],[2,3,4]])>>> aarray([[1, 2, 3],       [2, 3, 4]])>>> b = np.ones((2,3))          #默认类型为浮点型float64>>> barray([[ 1.,  1.,  1.],       [ 1.,  1.,  1.]])>>> b += a                      #这里整型int32被转化为float64>>> barray([[ 2.,  3.,  4.],       [ 3.,  4.,  5.]])>>> a += b        Traceback (most recent call last):  File "", line 1, in 
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int32') with casting rule 'same_kind'

上面的例子a+=b出现错误,这是因为numpy在操作不同类型的数据时,会朝着更精确的数据类型进行转化(类似于C语言中的向上转型)。

>>> from numpy import pi          #pi即PI,圆周率>>> a = np.ones(3, dtype=np.int32)>>> b = np.linspace(0,pi,3)    >>> b.dtype.name'float64'>>> c = a+b>>> carray([ 1.        ,  2.57079633,  4.14159265])  #转型>>> c.dtype.name'float64'>>> d = np.exp(c*1j)>>> darray([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,       -0.54030231-0.84147098j])>>> d.dtype.name'complex128'                                #复数型

numpy中可以使用很多“非数组”操作符来对数组进行操作,如求和sum,取平均mean。也可以通过设定axis参数来对特定的轴进行操作。

>>> a = np.array([[1,2,3],[2,3,4]])>>> aarray([[1, 2, 3],       [2, 3, 4]])>>> a.sum()   #求和15>>> a.min()   #求最小1>>> a.max()   #求最大4>>> a.sum(axis=0)  #求每列的和array([3, 5, 7])>>> a.sum(axis=1)  #求每行的和array([6, 9])>>> a.min(axis=1)  #求每行的最小值array([1, 2])>>> a.cumsum(axis=1)  #求每行的累积和array([[1, 3, 6],       [2, 5, 9]], dtype=int32)

通用操作

numpy中也有我们常见的数学函数sinexp等,但在numpy中这些函数是对数组中所有元素进行全局操作,与以往的函数不同,这里输入输出都为数组。

>>> a = np.arange(3)   >>> aarray([0, 1, 2])>>> np.exp(a)   #对其中每个元素进行exp操作array([ 1.        ,  2.71828183,  7.3890561 ])>>> np.sqrt(a)  #对其中每个元素进行sqrt操作(平方根)array([ 0.        ,  1.        ,  1.41421356])>>> b = np.array([2., -1., 4.])>>> np.add(a, b)   #两个数组相加array([ 2.,  0.,  6.])

numpy中的一维数组也可以进行索引、切片和迭代,这个和python中的lists有着相似的功能。

>>> a = np.arange(10)**3    #数组中0-9每个元素对其3次方>>> a   array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])>>> a[2]                    #取第2+1个元素8>>> a[2:5]                  #取第2+1到第5+1个元素array([ 8, 27, 64])>>> a[:6:2] = -1000         # 与 a[0:6:2] = -1000相同; 从开始到第6+1个位置, 每两个元素设为-1000>>> aarray([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])>>> a[ : :-1]               # 翻转 aarray([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])>>> for i in a:             #打印a中的元素(每个元素+1打印)...     print(i+1)  730513344217126-99928-9992-999

对于多维的数组,可以对其特定“轴”(axis)进行操作:

import numpy as np>>> def f(x,y):...     return x+y>>> a = np.fromfunction(f,(5,4),dtype=int)  #通过函数构造二维数组,函数参数为数组的坐标>>> aarray([[0, 1, 2, 3],       [1, 2, 3, 4],       [2, 3, 4, 5],       [3, 4, 5, 6],       [4, 5, 6, 7]])>>> a[2,3]                  #取第2+1行第3+1个元素5>>> a[1,:]                  #取第1+1行的元素array([1, 2, 3, 4])>>> a[:,2]                  #取第2+1列的元素array([2, 3, 4, 5, 6])>>> a[0:2,:]                #取第1-3行(不包括3)的元素array([[0, 1, 2, 3],       [1, 2, 3, 4]])>>> a[-1]                   #取最后一行的元素array([4, 5, 6, 7])

numpy中也有一种用法可以在多维数组简洁表示,使用dots(...)来表示同样数量的,比如:

x为秩为5的数组(有5个axis)
x[1,2,...]相当于x[1,2,:,:,:]
x[...,3]相当于x[:,:,:,:,3]
x[4,...,5,:]相当于x[4,:,:,5,:]

>>> c = np.array( [[[  0,  1,  2],               # 三维数组(包括两个二维数组)...                 [ 10, 12, 13]],...                [[100,101,102],...                 [110,112,113]]])>>> c.shape(2, 2, 3)>>> c[1,...]                                   # 与 c[1,:,:] 或 c[1] 相同array([[100, 101, 102],       [110, 112, 113]])>>> c[...,2]                                   # 等同于 c[:,:,2]array([[  2,  13],       [102, 113]])

在对多维数组进行迭代时,默认对第一维进行迭代:

>>> a = np.array([[0, 1, 2, 3],                  [1, 2, 3, 4],                  [2, 3, 4, 5],                  [3, 4, 5, 6],                  [4, 5, 6, 7]])>>>for row in a:...     print(row)[0 1 2 3][1 2 3 4][2 3 4 5][3 4 5 6][4 5 6 7]

可以使用flat来对数组中所有单个元素进行迭代:

>>>for element in a.flat:...     print(element)01231234234534564567

形状(shape)操作

每个数组对象都有一个对应元素数量的形状

>>> a = np.floor(10*np.random.random((3,4)))>>> aarray([[ 2.,  8.,  0.,  6.],       [ 4.,  5.,  1.,  1.],       [ 8.,  9.,  3.,  6.]])>>> a.shape         #这里的a的形状为(3,4)也就是三行四列(3, 4)

数组的形状是可以通过不同的命令进行改变的

>>> a.ravel()        #将数组进行平铺array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])>>> a.reshape(6,2)   # 返回一个改变形状的数组array([[ 2.,  8.],       [ 0.,  6.],       [ 4.,  5.],       [ 1.,  1.],       [ 8.,  9.],       [ 3.,  6.]])>>> a.T            # 返回一个a的转置array([[ 2.,  4.,  8.],       [ 8.,  5.,  9.],       [ 0.,  1.,  3.],       [ 6.,  1.,  6.]])>>> a.T.shape      #a转置的形状(4, 3)>>> a.shape        #a的形状(3, 4)

reshape命令与resize命令功能相同,只是resize命令在自身上面进行改动

>>> aarray([[ 2.,  8.,  0.,  6.],       [ 4.,  5.,  1.,  1.],       [ 8.,  9.,  3.,  6.]])>>> a.resize((2,6))>>> a                         #注意:a发生了变化array([[ 2.,  8.,  0.,  6.,  4.,  5.],       [ 1.,  1.,  8.,  9.,  3.,  6.]])

如果reshape中某个参数赋予-1时,则这个参数会根据另一个参数进行自动填充

>>> a.reshape(3,-1)         #之前a.shape为(2,6),reshape(3,-1)相当于(3,4)array([[ 2.,  8.,  0.,  6.],       [ 4.,  5.,  1.,  1.],       [ 8.,  9.,  3.,  6.]])

数组合并操作

数组之间可以相互进行合并,通过合并轴(axis)来实现

>>> import numpy as np>>> a = np.floor(10*np.random.random((2,2)))  #产生2×2的数组,元素通过floor函数去掉后面的小数点>>> aarray([[ 1.,  0.],       [ 3.,  2.]])>>> b = np.floor(10*np.random.random((2,2)))  >>> barray([[ 1.,  3.],       [ 1.,  8.]])>>> np.vstack((a,b))           #垂直叠加数组array([[ 1.,  0.],       [ 3.,  2.],       [ 1.,  3.],       [ 1.,  8.]])>>> np.hstack((a,b))           #水平叠加数组array([[ 1.,  0.,  1.,  3.],       [ 3.,  2.,  1.,  8.]])

注意,在多于二维数组的操作中,vstack对数组中的第二轴进行堆叠,而hstack则对第一轴进行堆叠。

对多维数组进行切片

使用hspit函数可以对数组在水平轴上进行切割,可以指定切割后有多少相似数组数量,和切割后有多少列来进行切割。

>>> a = np.floor(10*np.random.random((2,12)))>>> aarray([[ 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)   # 切割成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))   # 在第三列和第四列分别开刀[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可以对数组进行垂直切割。

复制和赋值

当在操作数组的时候,赋值和复制操作是不同的,这里需要注意。

>>> a = np.arange(12)>>> b = a            # 创造一个新的对象b,>>> b is a           # a和b指向同一个数组,只是名称不同True>>> b.shape = 3,4    # 改变b的形状,a的形状也随之改变>>> a.shape(3, 4)

为什么会这样,因为python在传递时传递的是引用,类似于C++中的引用,上面的a和b其实是完全相同的,因为它们指向一个相同的对象,只是操作时的名称不同。如果想复制一个新的对象而不是引用,则需要使用其他操作符。

>>> c = a.view()>>> c is aFalse>>> c.base is a                        # c是拥有a里面元素的一个模子True>>> c.flags.owndataFalse>>>>>> c.shape = 2,6                      # a的形状并没有改变>>> a.shape(3, 4)>>> c[0,4] = 1234                      # a的数据发生了改变>>> aarray([[   0,    1,    2,    3],       [1234,    5,    6,    7],       [   8,    9,   10,   11]])

这里view只是模子,但其实数据还是公用的,接下来的copy操作则实现了完全的复制

>>> d = a.copy()                          # d是一个新的对象,内容是a的复制品>>> d is aFalse>>> d.base is a                           # d与a并不共享数据False>>> d[0,0] = 9999>>> a                                     # b改变,a不改变array([[   0,   10,   10,    3],       [1234,   10,   10,    7],       [   8,   10,   10,   11]])

广播

广播是numpy一个非常强大的功能。你可以在一个数组中对其所有元素同时进行相同的操作,也可以同时操作两个及以上相同形状的多维数组,对其中的元素进行操作:

>>> a = np.array([1.0, 2.0, 3.0])>>> b = np.array([2.0, 2.0, 2.0])>>> a * b                             #注意,这里是a,b相对应的每个元素进行了相乘array([ 2.,  4.,  6.])>>> a = np.array([1.0, 2.0, 3.0])>>> b = 2.0                           #同上>>> a * barray([ 2.,  4.,  6.])

关于广播功能还有很多,这里只进行简单的介绍。

更多请看:

高级索引功能

numpy中除了通过特定的整数和切片进行访问,还有很多高级的索引访问功能:

>>> a = np.arange(12)**2                       # 对前12个元素进行平方>>> i = np.array( [ 1,1,3,8,5 ] )              # 创建一个“索引”数组>>> a[i]                                       # 取出相应索引位置的元素array([ 1,  1,  9, 64, 25])>>>>>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] )      # 二维“索引”数组>>> a[j]                                       # 取出的元素数组与j形状相同array([[ 9, 16],       [81, 49]])

再举一个例子,下面这段程序模拟了从一个“着色板”里面取出颜色汇成一个色彩图像。

>>> palette = np.array( [ [0,0,0],                # 黑...                       [255,0,0],              # 红...                       [0,255,0],              # 绿...                       [0,0,255],              # 蓝...                       [255,255,255] ] )       # 白>>> image = np.array( [ [ 0, 1, 2, 0 ],           # 每个值和颜色数组对应...                     [ 0, 3, 4, 0 ]  ] )>>> palette[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)>>> aarray([[ 0,  1,  2,  3],       [ 4,  5,  6,  7],       [ 8,  9, 10, 11]])>>> i = np.array( [ [0,1],                       ...                 [1,2] ] )>>> j = np.array( [ [2,1],                      ...                 [3,3] ] )>>>>>> a[i,j]                                    array([[ 2,  5],       [ 7, 11]])>>>>>> a[i,2]array([[ 2,  6],       [ 6, 10]])>>>>>> a[:,j]                                    array([[[ 2,  1],        [ 3,  3]],       [[ 6,  5],        [ 7,  7]],       [[10,  9],        [11, 11]]])

为了程序的美观和效率,一般这样使用:

>>> l = [i,j]>>> a[l]                                       # 相当于a[i,j]array([[ 2,  5],       [ 7, 11]])

深度学习常用的几个numpy函数

numpy.prod:返回数组内元素的乘积

>>> np.prod([1.,2.])    # 返回一维数组内元素的乘积2.0>>> np.prod([[1.,2.],[3.,4.]])   # 返回二维数组里面所有元素的乘积24.0>>> np.prod([[1.,2.],[3.,4.]], axis=1)     # 将每列的元素进行乘积array([  2.,  12.])>>> x = np.array([1, 2, 3], dtype=np.uint8)   #还可以指定元素类型>>> np.prod(x).dtype == np.uintTrue>>> x = np.array([1, 2, 3], dtype=np.int8)>>> np.prod(x).dtype == np.intTrue

numpy.pad:将数组(矩阵)周围进行填充

>>> a = np.array([[1,2,3],[2,3,4],[3,4,5]])>>>aOut[4]: array([[1, 2, 3],       [2, 3, 4],       [3, 4, 5]])>>> np.lib.pad(a,1,'constant',constant_values=0)  #将a数组周围填充宽度为1的常数0Out[5]: array([[0, 0, 0, 0, 0],       [0, 1, 2, 3, 0],       [0, 2, 3, 4, 0],       [0, 3, 4, 5, 0],       [0, 0, 0, 0, 0]])

转载地址:http://dfovx.baihongyu.com/

你可能感兴趣的文章
MFC Attach()函数和Detach()函数
查看>>
because it is not a variable 编译错误解决方案
查看>>
SO_REUSEADDR
查看>>
[笔试题]交换两个数不使用第三方变量 深入理解按位异或运算符
查看>>
[原创]互联网金融App测试介绍
查看>>
jstl格式化日期
查看>>
深入理解jQuery中$.get、$.post、$.getJSON和$.ajax的用法
查看>>
PHP访问连接MYSQL数据库
查看>>
Javascript函数调用的四种模式
查看>>
paip.提升用户体验--提升java的热部署热更新能力
查看>>
js跳转页面方法
查看>>
XML--使用XML来将字符串分隔成行数据
查看>>
ESXI转HYPER-V,问题接二连三啊(VMDK转VHD)
查看>>
bcdedit
查看>>
asp.net ajax检查用户名是否存在代码
查看>>
利用jquery给指定的table动态添加一行、删除一行
查看>>
android 开源组件合集-UI篇(2013-11-07更新)
查看>>
[转]Multiple outputs from T4 made easy
查看>>
hdu 4597 + uva 10891(一类区间dp)
查看>>
js获取当前页面url网址等信息
查看>>