侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

python科学计算之narray对象用法

Python  /  管理员 发布于 7年前   157

写在前面

最近在系统的看一些python科学计算开源包的内容,虽然以前是知道一些的,但都属于零零碎碎的,希望这次能把常用的一些函数、注意项整理下。小白的一些废话,高手请略过^ _ ^。文章中的函数仅仅是为了自己好理解,并没有按照官方文档上的函数声明形式记录。

numpy.narray

numpy.narray创建

numpy.narray的构造方式挺多的,这里就不一一说明,因为一般情况下,在进行科学计算时是通过给定的数据文件来读取的,而读取时使用的是pandas,具体可参考官方文档,或者参见这位大牛的文章。

numpy.narray.shape & numpy.narray.reshape

numpy.narray的形状可以用numpy.narray.shape属性来获取,它返回的是narray形状的tuple,反映了各个轴的长度。

na_a = np.array([1,2,3,4]) #长度为4的一维数组na_b = np.array([[1,2,3,4],[5,6,7,8]]) #2行4列的二维数组out:#print na_a[1 2 3 4] #print na_b[[1 2 3 4]  [5 6 7 8]] #print na_a.shape(4,)#print na_b.shape (2, 4) 

numpy.narray.shape相当于一个c++的public成员,不仅可以获取,还可以通过它改变narray的形状。当某一轴指定为-1时,该轴的长度将通过其他轴来计算。

na_b.shape = (4,2)na_a.shape = (2,-1)out:#print na_b[[1 2] [3 4] [5 6] [7 8]]#print na_a [[1 2] [3 4]]

需要注意的是:通过shape属性改变narray的形状时,并没对narray元素内存中的位置改变,只是改变了外观,仅仅是换了件马甲。

当然,如果你熟悉了使用函数,不想使用属性来改变形状时,可以通过narray.reshape(),注意的是该函数返回的结果和原narray共享内存空间,换句话说,一个narray对象的改变将导致另一个narray也发生相应的改变。

na_c = na_b.reshape((4,2))na_c[0][0] = 100out:#print na_c[[1 2] [3 4] [5 6] [7 8]]#print na_c[[100 2] [ 3 4] [ 5 6] [ 7 8]]#print na_b[[100 2] [ 3 4] [ 5 6] [ 7 8]]

numpy.narray.dtype

narray元素的类型可以使用dtype属性来获取,当然也可以在构造narray对象时指定元素的类型,需要注意的是,在numpy中float是64位,而complex是128位的。这里的float和complex是python内置的数据类型,numpy也定义了自己的float等数据类型,而且更加的细化,比如float类型,numpy就有float16、float32、float64和float128.

af = np.array([1,2,3,4], dtype=float)ac = np.array([5,6,7,8], dtype=complex)af.dtypeac.dtypedtype('float64')dtype('complex128')

python的完整数据类型中有大部分是所占字节来细化的,完整的数据在typeDict中定义,可通过numpy.typeDict.values()来获取完整类型。numpy在多维数组上的计算很高效,但是在数值对象计算上却比python慢很多,所以在进行数值计算时应避免使用numpy。

numpy.narray.astype() 类型转换

numpy.narray.astype() 可以对narray对象中元素逐一进行类型转换。

a = np.array([1,2,3,4], dtype=np.float)a.dtypedtype('float64')b = a.astype(np.int32)b.dtypedtype('int32')c.dtypec = a.astype(np.complex)c.dtypedtype('complex128')

numpy.narray的自动生成

1.np.arange(start,end,step,dtype) 指定开始值、终值和步长生成一个等差数列,生成的narray中不包括end值。

2.np.linspace(start, end, element_nums, endpoint,dtype) 指定开始值、终值和元素个数生成一个等差数列,通过endpoint指定包不包括end,默认为True。

3.np.logspace(start, end, element_nums, base, endpoint,dtype) endpoint默认为True,base默认为10,该函数产生一个等比数列,元素为

4.np.zeros(dim,dtype)对维度为dim的narray对象初始化为0,数据类型为dtype

5.np.ones(dim, dtype) 对维度为dim的narray对象初始化为1,数据类型为dtype

6.np.empty(dim,dtype) 该函数相当于对narray对象分配内存空间,但不进行初始化,所以切不可认为产生的元素为0。

7.np.full(dim, val, dtype) 产生维度为dim的narray对象并且全部初始为val,前面的zeros()和ones()可看作该函数的特殊形式。

8.上面函数的like版本,即np.zeros_like(object) 、np.ones_like(object) 、np.empty_like(object) 、np.full_like(object) ,这里的object是narray对象,这些函数产生的narray对象和上面一样,但narray的维度(shape)以及数据类型(dtype)是和传入的参数一样的,例如np.zeros_like(object) ==np.zeros(object.shape, object.dtype)。

9.fromstring(s, dtype)这个函数是比较又意思的,将字符串转换为一个narray对象, 我们先看看这个函数输出情况。

s="abcdefgh"np.fromstring(s)array([ 8.54088322e+194]) ## 这是什么鬼?### 输出一下dtype呢?dtype('float64')

显然,这里是按照float64类型存放的,那如果换一个数据类型呢?

np.fromstring(s,dtype=np.int8)array([ 97, 98, 99, 100, 101, 102, 103, 104], dtype=int8)

这个学过c语言的都应该知道是ASCII编码,也就可以看出,在python中一个字符是占8位,即一个字节的,继续看:

np.fromstring(s,dtype=np.int16)array([25185, 25699, 26213, 26727], dtype=int16)

这里改变数据类型位2个字节,那么应该是两个字符联立一起表示一个int16,25185=98*256+97,高位存放在低字节中,这是小端模式。OK,那如果我现在要存放的是[‘a','b'…'h']这样的narray对象呢?数据类型是什么?应该是‘|s1'

np.fromstring(s,'|S1')array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],  dtype='|S1')

frombuffer()也可以创建的narray对象,但此时创建的narray对象和原字符串是内存共享的,学过c++的都知道,string类型是只读类型,无法修改,所以在frombuffer()创建的narray无法做修改,如果要修改,请用fromstring()。

. fromfunction(fun, dim)通过自定义函数接口来创建narray对象,fun是一个函数名(看作指针),dim是一个创建对象的维度。

def fun(i): return i%4+1np.fromfunction(fun,(10,))array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.])

可见利用fromfunction()创建narray时,参数i是从0开始自增的,自增的次数是维度的大小给定的,上面给定的维度位(10,),是一个一维数组,i从0自增到9(共10次)。看另外一个例子:

def fun2(i,j): return (i+1)*(j+1)np.fromfunction(fun2,(9,9))array([[ 1., 2., 3., 4., 5., 6., 7., 8., 9.],  [ 2., 4., 6., 8., 10., 12., 14., 16., 18.],  [ 3., 6., 9., 12., 15., 18., 21., 24., 27.],  [ 4., 8., 12., 16., 20., 24., 28., 32., 36.],  [ 5., 10., 15., 20., 25., 30., 35., 40., 45.],  [ 6., 12., 18., 24., 30., 36., 42., 48., 54.],  [ 7., 14., 21., 28., 35., 42., 49., 56., 63.],  [ 8., 16., 24., 32., 40., 48., 56., 64., 72.],  [ 9., 18., 27., 36., 45., 54., 63., 72., 81.]])

行可以看作j的自增,列可以看作i的自增,所以可以看作是两个for循环。

numpy.narray的元素存取

可以按照python中list存取元素的方式。

a = np.arange(10) #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])a[5]  #5a[3:5] #[3,4]a[:5] #[0,1,2,3,4]a[:-1] #[0, 1, 2, 3, 4, 5, 6, 7, 8]### 也可以指定步长,通过第三个数指定a[1:-1:2] #从开始到结束,没隔两个数取一次 array([1, 3, 5, 7])a[5:1:-2] #反向取 array([5, 3])

注意,通过这种方式取的新narray和原始narray内存共享,所以任何一个改变,另一个也将改变。 除此之外,numpy还提供了一下几个存取方式: 使用list存取,list的每个元素作为下标,这种方式得到的新narray和原始narray不共享内存。

a = np.arange(10)a[[1,1,7,7]] #array([1, 1, 7, 7])

使用narray提取新数组,narray的元素作为下标,得到的新narray维度和参数narray维度相同。这个有点绕,看个例子吧:

a[np.array([2,1,3,6])] #array([2, 1, 3, 6])a[np.array([[2,1,3,6],[7,4,6,1]])] ## ## array([[2, 1, 3, 6],  [7, 4, 6, 1]])

使用bool数组提取,提取bool数组中为True的下标元素:

a[np.array([True, False,True,False,False,False,True,False,False,False])]## array([0, 2, 6])a[np.array([True,False,True,False,False,False,True,False,False,False])]=-1,-2,-3print a #array([-1, 1, -2, 3, 4, 5, -3, 7, 8, 9])

多维数组

请先看一张图:

左边是用切片方式提取右边6*6的narray对象元素。这种提取元素方式和原narray对象内存共享。

这里个人的理解,利用切片方式提取的新narray和原narray是内存共享的,而使用列表、bool数组等方式则不共享,原因很简单,利用切片方式,例如a[3:5],是从第三个元素到第5个元素(不包括),那么是用元素所占字节来移动的,就像c中的指针,这样比较便利。而其他方式是用下标,这些下标往往不连续,如果用指针方式的话则要来回移动,比较麻烦。所以不提供内存共享这种方式。

在这之前我们使用切片都是通过在[]中指定起点、终点以及步长,如果要单独创建切片对象呢?使用slice对象,创建的方式很简单,把[]中的:替换为None。

a = np.arange(0,60,10).reshape(-1,1)+np.arange(6)### 广播,后面会说到array([[ 0, 1, 2, 3, 4, 5],  [10, 11, 12, 13, 14, 15],  [20, 21, 22, 23, 24, 25],  [30, 31, 32, 33, 34, 35],  [40, 41, 42, 43, 44, 45],  [50, 51, 52, 53, 54, 55]])a[::2,2:]## array([[ 2, 3, 4, 5],  [22, 23, 24, 25],  [42, 43, 44, 45]])idx = slice(None,None,2),slice(2,None)a[idx]##array([[ 2, 3, 4, 5],  [22, 23, 24, 25],  [42, 43, 44, 45]])

同时,numpy提供了IndexExpression类的对象s_来方便slice的创建。

np.s_[::2,2:]## (slice(None, None, 2), slice(2, None, None))

结构体数组

numpy提供了和c类似的结构体数组,并且相互之间能够读取,以一个例子来说明:

## 创建persontype类型persontype=np.dtype({ 'names':['name','age','weight'], 'formats':['S30','i','f']}, align=True)## 创建结构体数组a=np.array([("zhang",20,55.5), ("wang",24,65.2)], dtype=persontype)

persontype有两个key,names和formats,names是以字典的方式标明结构体所含的字段,formats是对相应字段的数据类型。S30表示长度不超过30个字节的字符串,i相当于np.int32,f相当于np.float32,下面创建结构体数组的时候指定数据类型是我们创建的persontype。

## print aarray([('zhang', 20, 55.5  ), ('wang', 24, 65.19999695)],  dtype={'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40, 'aligned':True})## print a[0]('zhang', 20, 55.5)## a[0].dtypedtype({'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40}, align=True)## a[0]["name"]'zhang'b=a['age'] ## 20 24b[0]=50## print a[0]('zhang', 50, 55.5)

通过tostring()和tofile()可以将结构体数组写入文件,并可以通过c读取,由于c中的结构体存在对齐,所以在python创建结构体数组时也需要使用相应的对齐方式,这一点通过align来指定,True为对齐,False不对齐。

narray内存结构

以二维narray对象为例,我们来看看narray对象在内存中的结构。

a = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32)

该二维数组的结构如下图:

左边时一个结构体,描述了该narray对象的基本信息,包括数据类型(np.float32)、维度(轴的数量)、每个轴的数据个数、每个轴相邻元素的字节差、最后是存放数据的内存地址。通过切片方式得到的新narray就是在data字段表示的内存上获得原始narray的视图,我们来看看:

b=a[::2,::2]## barray([[ 0., 2.],  [ 6., 8.]], dtype=float32)## b.strides(24, 8)

获得的新narray.strides发生了变化,而这个变化也刚好是每个轴相邻元素跨越的字节数。narray的数据在内存上的排列有两种形式,分别是C和FORTRAN格式,上面我们展示的就是C的格式,第0轴是最上位的,也就是说,第0轴作为行,所以第0轴的相邻元素跨越的字节数是最多的(比如这里为3*4=12),而FORTRAN结构与C格式相反,它是第1轴跨越的字节数最多。numpy默认是C格式,如果想改成FORTRAN的格式,只需要在创建narray的时候设置order=‘F'。narray的flags属性描述了存储区的一些属性:

## a.flagsC_CONTIGUOUS : True  #C语言格式F_CONTIGUOUS : False #Fortran语言格式OWNDATA : True   #数组是否拥有该存储区,如果是一个narray的视图则不拥有WRITEABLE : True  #是否可写 (改变其中数据)ALIGNED : True   # 对齐UPDATEIFCOPY : False

OK,这里引出一个东东,如果要将a进行转置,我们是需要将需要将a顺时针旋转90°,那么还有上面简单的方法?我们先看看a.T.flags:

## a.T.flags C_CONTIGUOUS : False F_CONTIGUOUS : True OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False

从这上面可以看到,对于a的转置,numpy是将其内存格式改变了,从C语言格式变成了Fortran的格式,并且转置是a的一个视图。这样的方式比旋转方式更加快速。

以上这篇python科学计算之narray对象用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


  • 上一条:
    Python:slice与indices的用法
    下一条:
    python运用pygame库实现双人弹球小游戏
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客