是否可以修剪结构化numpy数组的零''记录'而不复制它;即,在开始或结束时为“未使用的”零条目释放的空闲内存;实际上,我只对最后修剪零感兴趣。
1d数组有内置函数numpy.trim_zeros()
。它的返回值:
返回:
trimmed:1-D数组或序列
修剪输入的结果。保留输入数据类型。
但是,我不能说这是否不会创建副本并且只释放内存。我不够精通从源代码中告诉它的行为。
更具体地说,我有以下代码:
import numpy
edges = numpy.zeros(3, dtype=[('i', 'i4'), ('j', 'i4'), ('length', 'f4')])
# fill the first two records with sensible data:
edges[0]['i'] = 0
edges[0]['j'] = 1
edges[0]['length'] = 2.0
edges[1]['i'] = 1
edges[1]['j'] = 2
edges[1]['length'] = 2.0
# list memory adress and size
edges.__array_interface__
edges = numpy.trim_zeros(edges) # does not work for structured array
edges.__array_interface__
更新
我的问题有些“双重”:
1)内置函数是否只是释放内存还是复制数组?
答案:
副本创建一个切片(= view);[ipython console] import numpy; numpy??
(另请参阅Resize NumPy array to smaller size without copy和View onto a numpy array?)
2)为结构化数组提供类似功能的解决方案是什么?
答案:
begin=(edges!=numpy.zeros(1,edges.dtype)).argmax()
end=len(edges)-(edges!=numpy.zeros(1,edges.dtype))[::-1].argmax()
# 1) create slice without copy but no memory is free
goodedges=edges[begin:end]
# 2) or copy and free memory (temporary both arrays exist)
goodedges=edges[begin:end].copy()
del edges
答案 0 :(得分:1)
trim_zeros
函数无法识别复合dtype上的零。 您可以begin=(edges!=zeros(1,edges.dtype)).argmax()
找到它们
和end=len(edges)-(edges!=zeros(1,edges.dtype))[::-1].argmax()
。然后goodedges=edges[begin:end]
是有趣的数据。
trim_zeros
函数不释放内存:退货------- 修剪:1-D阵列或序列。 修剪输入的结果。保留输入数据类型。
所以我认为你必须手动完成:goodedges=edges[begin:end].copy();del edges
。
答案 1 :(得分:1)
要扩展我的评论,让我们在一个简单的整数数组上尝试trim_zeros
:
In [252]: arr = np.zeros(10,int)
In [253]: arr[3:8]=np.ones(5)
In [254]: arr
Out[254]: array([0, 0, 0, 1, 1, 1, 1, 1, 0, 0])
In [255]: arr1=np.trim_zeros(arr)
In [256]: arr1
Out[256]: array([1, 1, 1, 1, 1])
现在比较__array_interface__
词典:
In [257]: arr.__array_interface__
Out[257]:
{'descr': [('', '<i4')],
'shape': (10,),
'version': 3,
'strides': None,
'data': (150760432, False),
'typestr': '<i4'}
In [258]: arr1.__array_interface__
Out[258]:
{'descr': [('', '<i4')],
'shape': (5,),
'version': 3,
'strides': None,
'data': (150760444, False),
'typestr': '<i4'}
shape
反映了我们想要的变化。但请查看data
指针,... 432和... 444。 arr1
只是在同一个缓冲区中指向12个字节(3个整数)。
如果我删除arr
或重新分配{偶数arr=arr1
),则arr1
会继续指向此数据缓冲区。 numpy
保留某种引用计数,并且仅在所有引用都消失时才回收数据缓冲区。
trim_zeros
的代码是(在ipython
中使用'??'获取)
File: /usr/lib/python3/dist-packages/numpy/lib/function_base.py
def trim_zeros(filt, trim='fb'):
first = 0
trim = trim.upper()
if 'F' in trim:
for i in filt:
if i != 0.: break
else: first = first + 1
last = len(filt)
if 'B' in trim:
for i in filt[::-1]:
if i != 0.: break
else: last = last - 1
return filt[first:last]
工作在最后一行,并清楚地返回一个切片,一个视图。大多数代码处理2个修剪选项(F和B)。请注意,它使用迭代来查找first
和last
非零。对于在开头或结尾只有几个额外0的数组,这应该没问题。但这并不是SO问题经常寻求的“矢量化”操作。
在此问题出现之前,我甚至不知道trim_zeros
存在,但我对其代码和行动并不感到惊讶。
在另一方面,这是创建edges
数组的更紧凑方式。
In [259]: edges =np.zeros(3, dtype=[('i', 'i4'), ('j', 'i4'), ('length', 'f4')])
In [260]: edges[:2]=[(0,1,2.0),(1,2,2.0)]
删除您可以使用的所有zero
元素:
edges[edges!=numpy.zeros(1,edges.dtype)]
这是一份副本。它确实删除了“嵌入”零,但如果只有零填充在前面的插槽中,那么这可能不是问题。
如果您在列表中收集edges
数据并在最后构建数组,则可能根本不需要此修剪:
edges1 = np.array([(0,1,2.0),(1,2,2.0)], dtype=edges.dtype)