本文摘自《用Python做科学计算》,版权归原作者所有。

上一篇讲到:NumPy-快速处理数据--ndarray对象--数组的创建和存取

接下来接着介绍多维数组的存取、结构体数组存取、内存对齐、Numpy内存结构

一、多维数组的存取

多维数组的存取和一维数组类似,因为多维数组有多个轴,因此它的下标需要用多个值来表示,NumPy采用组元(tuple)作为数组的下标。如二维数组需要(x, y)的元组标记一个数组元素;三维数组需要(x, y, z)的元组标记一个元素。

如下图所示,a为一个6x6的二维数组,图中用颜色区分了各个下标以及其对应的选择区域。

 >>> a
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[0, 3:5]#黄色部分
array([3, 4])
>>> a[4:, 4:]#蓝色部分
array([[44, 45],
[54, 55]])
>>> a[:, 2]#棕色部分
array([ 2, 12, 22, 32, 42, 52])
>>> a[2::2, ::2]#青色部分
array([[20, 22, 24],
[40, 42, 44]])

如何创建这个6×6的二维数组?

数组a实际上是一个加法表,纵轴的值为0, 10, 20, 30, 40, 50;横轴的值为0, 1, 2, 3, 4, 5。纵轴的每个元素都和横轴的每个元素求和,就得到图中所示的数组a。你可以用下面的语句创建它:

 np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6)

多维数组同样也可以使用整数序列和布尔数组进行存取。

 >>> a[(0, 1, 2, 3, 4), (1, 2, 3, 4, 5)]#取出坐标为(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)的元素
array([ 1, 12, 23, 34, 45])
>>> a[3:, [0, 2, 5]]#取出第3, 4, 5行,第0, 2, 5列的元素
array([[30, 32, 35],
[40, 42, 45],
[50, 52, 55]])
>>> mask = np.array([1, 0, 1, 0, 0, 1], dtype=np.bool)#先制造出一个布尔数组
>>> mask
array([ True, False, True, False, False, True], dtype=bool)
>>> a[mask, 2] #取出第二列下标为True的元素
array([ 2, 22, 52])

二、结构体数组

类似C语言中的结构体数组,在NumPy中也很容易对这种结构数组进行操作。只要NumPy中的结构定义和C语言中的定义相同,NumPy就可以很方便地读取C语言的结构数组的二进制数据,转换为NumPy的结构数组。

 >>> personType = np.dtype({'names':['name', 'age', 'weight'],\
'formats':['S32', 'i', 'f']})#创建personType数据类型
#字典有两个关键字:names,formats。每个关键字对应的值都是一个列表。
#names定义结构中的每个字段名,而formats则定义每个字段的类型:
# S32 : 32个字节的字符串类型
# i :32bit的整数类型,相当于np.int32
# f :32bit的单精度浮点数类型,相当于np.float32
>>> personType
dtype([('name', 'S32'), ('age', '<i4'), ('weight', '<f4')])
#描述结构类型的方法: 一个包含多个组元的列表,其中形如 (字段名, 类型描述)
#的组元描述了结构中的每个字段。类型描述前面的 '|', '<' 等字符用来描述字段
#值的字节顺序:
# | :忽视字节顺序
# < : 低位字节在前
# > : 高位字节在前
>>> a = np.array([('zhang', 32, 75.5), ('wang', 24, 65.2)], dtype=personType )
>>> a[0] #读取结构体数组的第0个结构元素
('zhang', 32, 75.5)
>>> a[1] #读取结构体数组的第1个结构元素
('wang', 24, 65.19999694824219)
>>> a[0].dtype
dtype([('name', 'S32'), ('age', '<i4'), ('weight', '<f4')])
>>> c = a[1] #c和a[1]共享同一块内存
>>> c['name'] = 'li'#修改c的字段
>>> a[1]['name']#则a[1]相应的字段也被修改
'li'
>>> a[0]['name']#读取a[0]字段的name成员
'zhang'
>>> b = a[:]['age']#或者 a['age']
>>> b
array([32, 24])
>>> b[0] = 40 #通过b[0]修改a[0]['age']
>>> a[0]['age']
40
>>> a.tofile('d:\\test.bin')
#调用a.tostring或者a.tofile方法,可以直接输出数组a的二进制形式

利用下面的C语言程序可以将test.bin文件中的数据读取出来。

三、内存对齐

C语言的结构体为了内存寻址方便,会自动的添加一些填充用的字节,这叫做内存对齐。内存对齐与操作系统以及编译器有关。例如如果把下面的name[32]改为name[30]的话,由于内存对齐问题,在name和age中间会填补两个字节,最终的结构体大小不会改变。因此如果numpy中的所配置的内存大小不符合C语言的对齐规范的话,将会出现数据错位。为了解决这个问题,在创建dtype对象时,可以传递参数align=True,这样numpy的结构数组的内存对齐和C语言的结构体就一致了。

 #include <stdio.h>

 struct person
{
char name[];
int age;
float weight;
};//创建结构体数据类型 struct person p[];//定义长度为2的一维结构体数组 int main (void)
{
FILE *fp;
int i;
fp=fopen("d:\\test.bin","rb");//以二进制只读方式打开文件
fread(p, sizeof(struct person), , fp);//读取的内容放在结构体数组p[2]中
fclose(fp);
for(i=;i<;i++)
printf("%s %d %f\n", p[i].name, p[i].age, p[i].weight);
getchar();
return ;
}
/*
在VC++6.0输出结果是:
----------------------------
zhang 40 75.500000
li 24 65.199997 Press any key to continue
----------------------------
*/

结构类型中可以包括其它的结构类型,下面的语句创建一个有一个字段f1的结构,f1的值是另外一个结构,它有字段f2,其类型为16bit整数。

 >>> np.dtype([('f1', [('f2', np.int16)])])#结构体套结构体
dtype([('f1', [('f2', '<i2')])])
#用dtype([ ])来定义结构体,[('f2', np.int16)]是一个结构体
#('f1', [('f2', np.int16)])是一个元组
#最外层用dtype([ ])再定义一层结构体

当某个字段类型为数组时,用组元的第三个参数表示,下面描述的f1字段是一个shape为(2,3)的双精度浮点数组:

 >>> np.dtype([('f0', 'i4'), ('f1', 'f8', (2, 3))])
dtype([('f0', '<i4'), ('f1', '<f8', (2, 3))])

用下面的字典参数也可以定义结构类型,字典的关键字为结构中字段名,值为字段的类型描述,但是由于字典的关键字是没有顺序的,因此字段的顺序需要在类型描述中给出,类型描述是一个组元,它的第二个值给出字段的字节为单位的偏移量,例如age字段的偏移量为25个字节:

 >>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)})
dtype([('surname', 'S25'), ('age', 'u1')])

四、Numpy内存结构

下面让我们来看看ndarray数组对象是如何在内存中储存的。

dtype对象则知道如何将元素的二进制数据转换为可用的值。如上图每32位表示一个有用数据

dim count表示数组维数,上图为2维数组

dimmension 3×3给出数组的shape

strides中保存的是当每个轴的下标增加1时,数据存储区中的指针所增加的字节数。例如图中的strides为12,4,即第0轴的下标增加1时,数据的地址增加12个字节:即a[1,0]的地址比a[0,0]的地址要高12个字节,正好是3个单精度浮点数的总字节数;第1轴下标增加1时,数据的地址增加4个字节,正好是单精度浮点数的字节数。

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

如果strides中的数值正好和对应轴所占据的字节数相同的话,那么数据在内存中是连续存储的。然而数据并不一定都是连续储存的,前面介绍过通过下标范围得到新的数组是原始数组的视图,即它和原始视图共享数据存储区域:

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

由于数组b和数组a共享数据存储区,而b中的第0轴和第1轴都是数组a中隔一个元素取一个,因此数组b的strides变成了24,8,正好都是数组a的两倍。 对照前面的图很容易看出数据0和2的地址相差8个字节,而0和6的地址相差24个字节。

元素在数据存储区中的排列格式有两种:C语言格式和Fortan语言格式。在C语言中,多维数组的第0轴是最上位的,即第0轴的下标增加1时,元素的地址增加的字节数最多;而Fortan语言的多维数组的第0轴是最下位的,即第0轴的下标增加1时,地址只增加一个元素的字节数。在NumPy中,元素在内存中的排列缺省是以C语言格式存储的,如果你希望改为Fortan格式的话,只需要给数组传递order="F"参数:

 >>> c = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32, order="F")
>>> c.strides
(4, 12)

NumPy-快速处理数据--ndarray对象--多维数组的存取、结构体数组存取、内存对齐、Numpy内存结构的更多相关文章

  1. C#引用c++DLL结构体数组注意事项(数据发送与接收时)

    本文转载自:http://blog.csdn.net/lhs198541/article/details/7593045 最近做的项目,需要在C# 中调用C++ 写的DLL,因为C# 默认的编码方式是 ...

  2. matlab学习笔记12_2创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段

    一起来学matlab-matlab学习笔记12 12_2 结构体 创建结构体数组,访问标量结构体,访问非标量结构体数组的属性,访问嵌套结构体中的数据,访问非标量结构体数组中多个元素的字段 觉得有用的话 ...

  3. NumPy-快速处理数据--ndarray对象--数组的创建和存取

    本文摘自<用Python做科学计算>,版权归原作者所有. NumPy为Python提供了快速的多维数组处理的能力,而SciPy则在NumPy基础上添加了众多的科学计算所需的各种工具包,有了 ...

  4. Python科学计算学习一 NumPy 快速处理数据

    1 创建数组 (1) array(boject, dtype=None, copy=True, order=None, subok=False, ndmin=0) a = array([1, 2, 3 ...

  5. Python科学计算:用NumPy快速处理数据

    创建数组 import numpy as np a=np.array([1,2,3]) b=np.array([[1,2,3],[4,5,6],[7,8,9]]) b[1,1]=10 print(a. ...

  6. c# 利用结构体获取json数据

    最近做微信支付,要获取用户的openid,调用接口后返回的是json格式的数据,我想在c#后台把数据逐一取出,网上查了查,找到以下方法: 1.首先调用接口,要有一个post数据到指定url并返回数据的 ...

  7. C结构体中数据的内存对齐问题

    转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...

  8. 字符设备驱动1:新的方式添加cdev + 在open函数中将文件私有数据指向设备结构体

    本例中,驱动入口处,使用cdev_add添加驱动,这点也可与字符设备驱动0:一个简单但完整的字符设备驱动程序对比一下. 另外主要讲xx_open实现文件私有数据指向设备结构体. 引子: 偶然看到,在j ...

  9. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

随机推荐

  1. 常用js、jquery 语句(句型)

    1.动态更改设置属性(class  style 都是属性) $("#sendPhoneNum").attr("class", "n_input3&qu ...

  2. 011PHP基础知识——运算符(四)

    <?php /** * 连接运算符: . 连接2个参数生成新的字符串: */ /*$str="中国"; $bbs="bbs.blog.com"; $new ...

  3. H.264采集、编码、传输的流程

    转载自H.264采集.编码.传输的流程 1 采集到的原始数据放入buf中 2 转化为yuv格式放入yuv conv.RGB24_to_YV12(buf, yuv,IMAGE_WIDTH, IMAGE_ ...

  4. L170 Autism Linked to Zinc Deficiency in Childhood

    While the exact cause of autism is unknown, its development in children has been linked to various g ...

  5. Linux系统在启动过程中启动级别发生错误的解决办法

    一.系统启动级别一共有六个: 0:系统停机模式,系统不可以正常启动 1:单用户模式, root权限,用于系统的维护,禁止远程登陆 2:多用户模式,没有NFS网络支持 3:完整的多用户文本模式,有NFS ...

  6. 策略模式-Java实现

    策略模式—Java实现 1. 现实需求 本人现在负责开发和维护考核督办系统,其中一个模块叫编写工作计划.是工作计划就要有时间,我们的各种提醒都做了,但是还是有人把x月的工作计划内容写到y月,真心无语了 ...

  7. jQuery 滑动选项卡jQuery tabslet

    Tabslet   Yet another jQuery plugin for tabs, lightweight, easy to use and with some extra features ...

  8. Kotlin Reference (五) Packages

    most from reference 包 源文件可以从包声明开始: package foo.bar fun baz() {} class Goo {} // ... 源文件的所有内容(如类和函数)都 ...

  9. Hibernate中用left join(左外连接)查询映射中没有关联关系的两个表记录问题

    一.问题背景 分账表split_summary结构如下: create table SPLIT_SUMMARY ( uuid VARCHAR2(32) not null, star_tdate VAR ...

  10. CSDN博客积分规则

    1.博客积分规则 博客积分是CSDN对用户努力的认可和奖励,也是衡量博客水平的重要标准.博客等级也将由博客积分唯一决定.积分规则具体如下: 每发布一篇原创或者翻译文章:可获得10分: 每发布一篇转载文 ...