我一直在使用pickle库来读取和编写numpy数组,但它们往往非常大。在我寻找是否有更好的方法的过程中,我在this页面(图表中的那个)找到了Mark的答案。基本上,将其存储为二进制文件似乎不仅是最快的读写,而且还占用最少的内存。所以我点击his github link并在第96行找到了我认为他用来保存ndarrays的代码。他的代码是:
class Binary(TimeArrStorage):
def save(self, arr, pth):
with open(pth, 'wb+') as fh:
fh.write(b'{0:s} {1:d} {2:d}\n'.format(arr.dtype, *arr.shape))
fh.write(arr.data)
sync(fh)
def load(self, pth):
with open(pth, 'rb') as fh:
dtype, w, h = str(fh.readline()).split()
return frombuffer(fh.read(), dtype=dtype).reshape((int(w), int(h)))
我的具体问题是,传递给第一次调用fh.write的字符串的含义是什么?我假设前面的" b"意思是二进制,但是{0:s} {1:d} {2:d}怎么样,特别是因为格式后括号内只有两个参数。第二个问题是这个方法可以用于任何数据类型的ndarray吗?第三个问题是,我是否需要调用sync方法(方法是在github页面的顶部定义的)?最后一个问题是,我查看arr.data返回的内容,如果arr是一个ndarray,它基本上是数据开始的内存位置,那么这段代码如何知道它到达了反对它试图写?
答案 0 :(得分:0)
我(来自另一个问题)
In [509]: arr
Out[509]:
array([[-1.0856306 , 0.99734545],
[ 0.2829785 , -1.50629471],
[-0.57860025, 1.65143654]])
我可以使用其属性格式化字符串:
In [510]: '%s %d %d'%(arr.dtype, *arr.shape)
Out[510]: 'float64 3 2'
示例中的格式在py3中给出了错误(在py2中它没问题):
In [500]: '{0:s} {1:d} {2:d}'.format(arr.dtype, *arr.shape)
...
TypeError: non-empty format string passed to object.__format__
没关系:
In [515]: '{0} {1} {2}'.format(arr.dtype, *arr.shape)
Out[515]: 'float64 3 2'
In [533]: '{0!s} {1:d} {2:d}'.format(arr.dtype, *arr.shape)
Out[533]: 'float64 3 2'
对于二维数组,arr.shape
是一个2元素元组,*arr.shape
扩展它。 SO有2d数组,有3个参数。
现在你提到它arr.data
确实看起来很有趣。我怀疑它们是指整个数据缓冲区内容,但这个特定属性是地址,而不是内容。
正如我在评论中提到的,np.save
基本上做同样的事情,初始块略大一些。如果这个代码有问题,坚持使用久经考验的np.save
会更明智。
查看np.lib.npyio.format
以查看完整的np.save
代码。它写一个标题,然后用以下内容写入数据缓冲区:
array.tofile(fp)
np.load
如果可以,则使用np.fromfile
,但会回退到使用frombuffer
。
在Py2中,这有效:
>>> arr=np.ones((2,3))
>>> b'{0:s} {1:d} {2:d}'.format(arr.dtype, *arr.shape)
'float64 2 3'