1. 程式人生 > >『Numpy』內存分析_numpy結構化數組

『Numpy』內存分析_numpy結構化數組

list AS 方法 mes cin 結構數組 urn 高級 修改

三、numpy的結構數組

『Numpy』內存分析_numpy.dtype內存數據解析方式指導

利用np.dtype可以構建結構數組,numpy.ndarray.base會返回內存主人的信息,文檔如下,

Help on getset descriptor numpy.ndarray.base:

base
Base object if memory is from some other object.

Examples
--------
The base of an array that owns its memory is None:

>>> x = np.array([1,2,3,4])

>>> x.base is None
True

Slicing creates a view, whose memory is shared with x:

>>> y = x[2:]
>>> y.base is x
True

1、建立結構數組

persontype = np.dtype({
    ‘names‘:[‘name‘,‘age‘,‘weight‘,‘height‘],
    ‘formats‘:[‘S30‘,‘i‘,‘f‘,‘f‘]}, align=True)
a = np.array([(‘Zhang‘,32,72.5,167),
              (‘Wang‘,24,65,170)],dtype=persontype)
a[‘age‘].base

array([(b‘Zhang‘, 32, 72.5, 167.),

(b‘Wang‘, 24, 65. , 170.)],

dtype={‘names‘:[‘name‘,‘age‘,‘weight‘,‘height‘],

‘formats‘:[‘S30‘,‘<i4‘,‘<f4‘,‘<f4‘],

‘offsets‘:[0,32,36,40],

‘itemsize‘:44,

‘aligned‘:True})

2、高級切片和普通切片的不同

In [26]: a.base
In [27]: a[0].base
In [28]: a[:1].base
Out[28]: array([123,   4,   5,   6,  78])
In [29]: a[[0,1]].base

In [30]: a.base is None
Out[30]: True
In [31]: a[0].base is None
Out[31]: True
In [32]: a[:1].base is None
Out[32]: False
In [33]: a[[0,1]].base is None
Out[33]: True

由上可見高級切片會開辟新的內存,復制被切出的數據,這是因為這種不規則的內存訪問使用原來的內存結構效率很低(邏輯相鄰元素內存不相鄰,標準的訪問由於固定了起始和步長相當於訪問相鄰元素,所以效率較高),拷貝出來就是連續的內存數組了。

3、高級切片且不開辟新內存的方法

回到上上小節的結構數組,

print(a[‘age‘].base is a)
print(a[[‘age‘, ‘height‘]].base is None)

True

True

我們通過指定內存解析方式,實現不開辟新內存,將原內存解析為高級切片指定的結構數組,

def fields_view(arr, fields):
    dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
    # print(dtype2)
    # {‘names‘:[‘age‘,‘weight‘], ‘formats‘:[‘<i4‘,‘<f4‘], ‘offsets‘:[32,36], ‘itemsize‘:40}
    # print([(name,arr.dtype.fields[name]) for name in fields])
    # [(‘age‘, (dtype(‘int32‘), 32)), (‘weight‘, (dtype(‘float32‘), 36))]
    # print(arr.strides)
    # (44,)
    return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)
‘‘‘
ndarray(shape, dtype=float, buffer=None, offset=0,
 |          strides=None, order=None)
 
參數 	類型 	作用
shape 	int型tuple 	多維數組的形狀
dtype 	data-type 	數組中元素的類型
buffer 		用於初始化數組的buffer
offset 	int 	buffer中用於初始化數組的首個數據的偏移
strides 	int型tuple 	每個軸的下標增加1時,數據指針在內存中增加的字節數
order 	‘C‘ 或者 ‘F‘ 	‘C‘:行優先;‘F‘:列優先
‘‘‘

v = fields_view(a, [‘age‘, ‘weight‘])
print(v.base is a)

v[‘age‘] += 10
print(‘+++‘*10)
print(v)
print(v.dtype)
print(v.dtype.fields)
print(‘+++‘*10)
print(a)
print(a.dtype)
print(a.dtype.fields)
True
++++++++++++++++++++++++++++++
[(42,  72.5) (34,  65. )]
{‘names‘:[‘age‘,‘weight‘], ‘formats‘:[‘<i4‘,‘<f4‘], ‘offsets‘:[32,36], ‘itemsize‘:40}
{‘age‘: (dtype(‘int32‘), 32), ‘weight‘: (dtype(‘float32‘), 36)}
++++++++++++++++++++++++++++++
[(b‘Zhang‘, 42,  72.5,  167.) (b‘Wang‘, 34,  65. ,  170.)]
{‘names‘:[‘name‘,‘age‘,‘weight‘,‘height‘], ‘formats‘:[‘S30‘,‘<i4‘,‘<f4‘,‘<f4‘], ‘offsets‘:[0,32,36,40], ‘itemsize‘:44, ‘aligned‘:True}
{‘name‘: (dtype(‘S30‘), 0), ‘age‘: (dtype(‘int32‘), 32), ‘weight‘: (dtype(‘float32‘), 36), ‘height‘: (dtype(‘float32‘), 40)}

這裏註意一下.dtype的’itemsize‘參數,表示添加一條(行)數據,內存增加了多少字節,由於保存了‘offsets‘偏移信息,我們生成的dtype展示的是一個稀疏的結構,但是每一行不會有多余的尾巴,這是因為空元素是由實元素記錄偏移量的空隙產生的。

4、view

『Numpy』numpy.ndarray.view_數組視圖_reshape、數組切片、數組內存開辟分析

如果兩者的itemsize相同,我們可以直接使用array.view(dtype=dtype)來指定數組內存數據的展示視圖形式,上面的代碼這樣修改一下,

def fields_view(arr, fields):
    dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
    return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)

v = fields_view(a, [‘age‘, ‘height‘])
a.view(dtype=v.dtype)
array([(52,  167.), (44,  170.)], 
      dtype={‘names‘:[‘age‘,‘height‘], ‘formats‘:[‘<i4‘,‘<f4‘], ‘offsets‘:[32,40], ‘itemsize‘:44})

當我們最後一個偏移取到行末尾即屬性‘height‘時,兩者itemsize相等,可以指定view方法解析,

print(v.dtype)
# {‘names‘:[‘age‘,‘height‘], ‘formats‘:[‘<i4‘,‘<f4‘], ‘offsets‘:[32,40], ‘itemsize‘:44}

print(a.dtype)
# {‘names‘:[‘name‘,‘age‘,‘weight‘,‘height‘], ‘formats‘:[‘S30‘,‘<i4‘,‘<f4‘,‘<f4‘], ‘offsets‘:[0,32,36,40], ‘itemsize‘:44, ‘aligned‘:True}

這是因為view本來用於解析內存數據的解析方式,對於結構數組就是每一行的解析方式,這個解析的方式(即輸入參數我們自建的dtype)當然必須和內存數據的描述參數(即內存從屬的數組的dtype)一致才行,否則解析數據無法對齊。

a.view(dtype=v.dtype)
array([(72,  167.), (64,  170.)], 
      dtype={‘names‘:[‘age‘,‘height‘], ‘formats‘:[‘<i4‘,‘<f4‘], ‘offsets‘:[32,40], ‘itemsize‘:44})

『Numpy』內存分析_numpy結構化數組