ndarray:n-dimensional array object,即多維數組對象,是python自帶的array對象的擴展,array對象和list對象的區別是array對象的每一個元素都是數值,而list保存的是每個元素對象的指針,而作為array對象的擴展,ndarray在科學計算中就非常適合並且功能強大。
創建ndarray
1. 使用列表對象創建ndarray
import bumpy as np
a = np.array([1,2,3,4])
以上為一種創建ndarray的方式,即用一個列表對象來創建,注意,ndarray中的所有元素類型都必須一致(atomic vector),上例中,如果其中一個元素為字符類型,則所有的元素都會自動轉換為字符類型,通過dtype屬性來獲取ndarray中每個元素的類型,同時numpy中還提供了numpy.typeDict來存放各種類型的簡稱-類型字典;
由於ndarray是多維數組對象,可以通過shape屬性來獲取數組的各維情況,並且可以通過reshape方法改變當前的形狀;
2. 使用numpy中特有函數創建ndarray
除了使用python中的列表對象來創建ndarray之外,numpy中還提供了一系列特定的函數用來創建ndarray
numpy.arange(0,1,0.1):arange和range類似,通過指定起始值、終止值、步長來創建數組,是一個前閉后開的區間,如該例創建的數組為:array([0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]);
numpy.linspace(0,1,10):linspace是通過指定起始值、終止值、元素個數來創建一個等差數組,默認為前閉后閉,通過設置endpoint=False可以對終止值設置是否包含;
numpy.logspace(0,1,12,base=2,endpoint=False):logspace是和linspace的區別是創建的是等比數組,默認以10為底,通過設置base改變底值;
numpy.zeros()、numpy.ones()、numpy.empty()等函數創建特定形狀的數組,和matlab中類似;
numpy.fromstring():通過字符串來創建數組,字符串的每一個字符占用一個字節的空間,也就是8個字節,通過指定dtype,創建不同的數組;當dtype=int8時,每個字符對應一個元素,當dtype=16時,兩個字符對應一個元素,並且以16進制保存(高位的字符需要乘以16);
numpy.fromfunction(func, (10,)):該函數通過指定一個創建函數和一個shape來創建數組,當shape只有一個元素(一維數組)時,func函數應該也只有一個參數,並且該參數自動從0開始遞增帶入得到一系列返回值,從而創建ndarray;
存取ndarray
1. 存取一維ndarray
ndarray的元素訪問支持python中的列表的訪問方式(下標以及切片)訪問ndarray元素,通過下標和切片訪問得到的新數組是原始數組的一個視圖(view),和原始數組共享存儲;
除了列表的訪問方式,ndarray還支持整數列表、整數數組、布爾數組等訪問方式,通過這些訪問方式得到的新數組是原始數組的拷貝,並不共享存儲;
整數列表的訪問會按照給定列表的元素作為下標依次訪問原始數組中的每個元素:
a = np.arange(10)
b = a[[3,3,-3,8]]
整數數組的訪問在列表的基礎上,訪問得到的新數組會保留數組的形狀;
布爾數組的訪問,指使用一個布爾數組,只訪問到布爾數組中True對應下標的元素;注意,只對布爾數組有效,如果是列表,則會講True和False當做1和0作為下標處理;
布爾數組的訪問通常由ufunc產生;
2. 存取多維數組
訪問多維數組需要指定多維的下標,在python中實現多維下標的方式是通過元組(tuple),由於 1,2 和 (1,2)表示的語義相同,所以用元組表示下標時,也變得非常自然;ndarray的多維數組中,可以通過元組中分別指定切片來訪問多維數組(得到的仍然是視圖);同時也可以通過數組和切片的組合、數組和數組的組合來訪問多維數組,記住將元組作為下標,元組中的每個元素分別對應某一維上的下標,則一切迎刃而解;
需要注意的是,使用切片是指定某一行或者某一列等(保留形狀),但是用整數數組訪問時,訪問的是某一個下標(不會保留形狀,只是簡單地將值取出);
如果一個多維數組訪問時,指定的下標小於維數,則剩余的維數下標默認全部訪問(相當於切片 : 代替);
如果用數組和數組的結合來訪問多維數組,則只有當兩個數組的形狀相同時,得到的數組和下標數組的形狀相同;
numpy中可以使用一個列數組和一個行數組相加得到一個二維數組;
結構數組
通過使用結構數組,可以實現類似C語言中struct的功能;結構數組使用numpy.dtype()實例,實例化時,使用一個字典指定結構的名稱和對應的類型(類型可以使用numpy.typeDict中的簡稱,字符串通過S32等來表示,32指定保存時的字符串長度,用以內存對齊);
結構數組除了數組用下標的訪問方式之外,還可以通過字段訪問;
通過numpy定義的結構數組可以通過tofile方法直接保存到文件中,並且該文件可以被c語言獲取結構;
a.tofile(’test.bin')
通過c語言讀取:
#include <stdio.h>
struct person
{
char name[32];
int age;
float weight;
}
struct person p[3];
void main(){
FILE *fp;
int i;
fp = fopen("test.bin","rb");
fread(p, sizeof(struct person), 2, fp);
fclose(fp);
for(i=0; i<2; i++){
printf("%s %d %f\n",p[i].name, p[i].age, p[i].weight);
}
}
內存結構
adarray的信息使用一個數組來描述,該數組引用兩個對象:dtype和data,其中data表示一個連續的數據存儲區域,並保存數組的形狀以及間隔,從而訪問連續存儲區域中的指定位置存放的數據,實現對數組的訪問;
如上圖,dtype指向元素類型的對象;
dim count表示維數,dimensions是一個長度為dim count的數組,指定數組每一維的長度;
strides是一個長度為dim count的數組,每個元素是一個整數值,用來指定各維元素的間隔,如上圖中表示第一維元素每增加1,則地址增加12,第二維元素每增加1,則地址增加4;
numpy中默認的數據存儲排序方式是c語言中的排序方式,即第一維是最上位的,第一維的值增加1時,地址增加的范圍最大,而在fortran語言中,第一維是最下位的,第一維增加1時,只增加一個元素的字節長度,如上例中,strides如果按照fortran語言中的排序方式,則應該為:(4,12),通過在定義數組時,指定order=“F”,來使用fortran語言的排序方式;
了解內存結構可以解釋以下問題:為什么切片訪問數組時,得到的數組是視圖,而通過數組訪問數組時,得到的數組是一份拷貝?
由於切片訪問數組時,只需要改變strides的值,就可以對數組進行另外一種方式的訪問,如如果存在數組a按照上圖的方式保存,則b = [::2,::2]得到一個新的數組時,只需要將strides改為(24,8)就可以,而data則可以引用相同的存儲區域;而當使用數組進行訪問時,由於並不能保證是等間隔分布的,無法通過改變其他屬性的方式保持數據不變,所以只能新建一份數據的拷貝來實現;
通過數組的flags屬性可以查看數據存儲區域的屬性;