NumPy-快速处理数据--ndarray对象--多维数组的存取、结构体数组存取、内存对齐、Numpy内存结构...
本文摘自《用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??v軸的每個元素都和橫軸的每個元素求和,就得到圖中所示的數組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内存结构...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mac下使用自带的apache与php
- 下一篇: 公司开户需要什么资料(新公司开户所需资料