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

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

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

一、多维数组的存取

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

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

 1 >>> a
 2 array([[ 0,  1,  2,  3,  4,  5],
 3        [10, 11, 12, 13, 14, 15],
 4        [20, 21, 22, 23, 24, 25],
 5        [30, 31, 32, 33, 34, 35],
 6        [40, 41, 42, 43, 44, 45],
 7        [50, 51, 52, 53, 54, 55]])
 8 >>> a[0, 3:5]#黄色部分
 9 array([3, 4])
10 >>> a[4:, 4:]#蓝色部分
11 array([[44, 45],
12        [54, 55]])
13 >>> a[:, 2]#棕色部分
14 array([ 2, 12, 22, 32, 42, 52])
15 >>> a[2::2, ::2]#青色部分
16 array([[20, 22, 24],
17        [40, 42, 44]])

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

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

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

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

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

二、结构体数组

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

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

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

三、内存对齐

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

 1 #include <stdio.h>
 2
 3 struct person
 4 {
 5     char name[32];
 6     int age;
 7     float weight;
 8 };//创建结构体数据类型
 9
10 struct person p[2];//定义长度为2的一维结构体数组
11
12 int main (void)
13 {
14     FILE *fp;
15     int i;
16     fp=fopen("d:\\test.bin","rb");//以二进制只读方式打开文件
17     fread(p, sizeof(struct person), 2, fp);//读取的内容放在结构体数组p[2]中
18     fclose(fp);
19     for(i=0;i<2;i++)
20         printf("%s %d %f\n", p[i].name, p[i].age, p[i].weight);
21     getchar();
22     return 0;
23 }
24 /*
25 在VC++6.0输出结果是:
26 ----------------------------
27 zhang 40 75.500000
28 li 24 65.199997
29
30 Press any key to continue
31 ----------------------------
32 */

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

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

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

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

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

1 >>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)})
2 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个字节,正好是单精度浮点数的字节数。

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

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

1 >>> b = a[::2,::2]
2 >>> b
3 array([[ 0.,  2.],
4        [ 6.,  8.]], dtype=float32)
5 >>> b.strides
6 (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"参数:

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

转载于:https://www.cnblogs.com/moon1992/p/4946717.html

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

  1. 一维数组,二维数组,三维数组,数组与指针,结构体数组,通过改变指针类型改变访问数组的方式

     打印数组中的每个元素,打印每个元素的地址: #include <stdio.h> #include <stdlib.h> void main(void) { int a[ ...

  2. C语言试题五十二之学生的记录由学号和成绩组称个,n名大学生得数据已在主函数中放入结构体数组a中,请编写函数fun,它的功能时:按分数的高低排列学生的记录,高分在前。

    1. 题目 请编写一个函数void function(Student a[], int n),其功能时:学生的记录由学号和成绩组称个,n名大学生得数据已在主函数中放入结构体数组a中,请编写函数fun, ...

  3. C语言试题五十一之已知学生的记录是由学号和学习成绩构成,n名学生的数据已存入s结构体数组中。请编写函数fun,该函数的功能是:找出成绩最高的学生记录,通过形参返回主函数(规定只有一个最高分)。

    1. 题目 请编写一个函数void function(Student a[], int n, Student *s),其功能时:已知学生的记录是由学号和学习成绩构成,n名学生的数据已存入s结构体数组中 ...

  4. dotnet C# 将 Byte 二进制数组使用不安全代码快速转换为 int 或结构体数组

    我在写一个有趣的 WPF 应用,我会不断收到从硬件发过来的数据,这些数据被使用 Byte[] 数组进行传输.我想要使用最快的方法转换为我的 int 数组或者转换为结构体数组,此时可以使用不安全代码的方 ...

  5. 【HDU】1305 Immediate Decodability(字典树:结构体数组,二维数组,链表/指针)

    一.用的二维数组 #include <iostream> #include <cstring> #include <algorithm> using namespa ...

  6. 【HDU】1251统计难题 (字典树:二维数组,结构体数组,链表,map)

    使用二维数组或者结构体数组都可以,但是在计数的时候有一点点小区别 一.结构体数组 #include <cstdio> #include <cstring> #include & ...

  7. matlab多维数组、结构体数组

    1.多维数组 第三维称为页,需要注意的是每一页存放的二维数组维度要一致,也就是行列数要一致... 1 2 3 4 5 6 7 a=[1,2;     3,4]; b=[2,2;     5,6]; A ...

  8. 怎么删除结构体数组中的一组数据_数据结构-栈

    数据结构-栈 1)栈的定义. 栈是只能通过访问它的一端来实数据存储和检索的一种线性数据结构,逻辑结构和线性表相同.特点在于运算有所限制:即主要特征是"后进先出"(先进后出). 在栈 ...

  9. java 结构体数组初始化_C数组结构体联合体快速初始化

    背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元 ...

最新文章

  1. WinRM设置信任主机
  2. 位图 查找重复 排序 存数据
  3. Socket通信(一)
  4. 【OC】【一秒就会】【collectionView 头部吸住功能】
  5. [caffe(一)]使用caffe训练mnist数据集
  6. RocketMQ Filtersrv
  7. Collection源码阅读
  8. AE 中的查找与定位,以城市查找为例
  9. Ubuntu14.04搭建Oracle instantClient 11.2.0.4并配置cx_Oracle5.1.2
  10. transient、volatile关键字
  11. 需求分析岗的一点总结
  12. “校内网”将不存在,“校内网”更名为“人人网”
  13. python录入数据,python处理写入数据教学教程
  14. ds12c887c语言程序,时钟芯片ds12c887的C51驱动程序
  15. 平生不会相思,才会相思,便害相思
  16. 代码写的多了就能成为一名优秀程序员吗
  17. BIM电子沙盘编辑软件BIMSHOW开启下载了
  18. 渗透项目(五):W1R3S
  19. android 调用系统图库剪切图片出现黑屏闪退
  20. NOKOV度量动捕软件教程(5):数据处理

热门文章

  1. Python3 strip()去除字符串首尾指定信息
  2. mybatis-plus自定义配置方式
  3. mybatis架构流程
  4. MyCat基本概念、配置文件及日志配置
  5. 北京卫生中级英语计算机考试成绩查询,2019年北京卫生专业技术资格成绩查询时间及入口...
  6. 给定的 columnmapping 与源或目标中的任意列均不匹配_闻歌研究 | 图文自动匹配任务研究调研...
  7. acme.sh签发Let‘s Encrypt证书
  8. sonar的安装以及使用
  9. 从源码角度看Android系统init进程启动过程
  10. seg显示时间——51程序