我需要组织一个包含命名数据块的数据文件。数据是NUMPY数组。但我不想使用numpy.save或numpy.savez函数,因为在某些情况下,数据必须通过管道或其他接口在服务器上发送。所以我想将numpy数组转储到内存中,压缩它,然后将其发送到服务器中。
我尝试过简单的泡菜,如下:
try:
import cPickle as pkl
except:
import pickle as pkl
import ziplib
import numpy as np
def send_to_db(data, compress=5):
send( zlib.compress(pkl.dumps(data),compress) )
..但这是一个非常缓慢的过程。
即使压缩等级为0(没有压缩),这个过程也很慢,只是因为酸洗。
有没有办法将numpy数组转换为没有pickle的字符串?我知道numpy允许获取缓冲区numpy.getbuffer,但对我来说,如何使用这个转储缓冲区来获取数组是不明显的。
答案 0 :(得分:4)
你绝对应该使用numpy.save
,你仍然可以在内存中使用它:
>>> import io
>>> import numpy as np
>>> import zlib
>>> f = io.BytesIO()
>>> arr = np.random.rand(100, 100)
>>> np.save(f, arr)
>>> compressed = zlib.compress(f.getvalue())
要解压缩,请反转过程:
>>> np.load(io.BytesIO(zlib.decompress(compressed)))
array([[ 0.80881898, 0.50553303, 0.03859795, ..., 0.05850996,
0.9174782 , 0.48671767],
[ 0.79715979, 0.81465744, 0.93529834, ..., 0.53577085,
0.59098735, 0.22716425],
[ 0.49570713, 0.09599001, 0.74023709, ..., 0.85172897,
0.05066641, 0.10364143],
...,
[ 0.89720137, 0.60616688, 0.62966729, ..., 0.6206728 ,
0.96160519, 0.69746633],
[ 0.59276237, 0.71586014, 0.35959289, ..., 0.46977027,
0.46586237, 0.10949621],
[ 0.8075795 , 0.70107856, 0.81389246, ..., 0.92068768,
0.38013495, 0.21489793]])
>>>
正如您所看到的,匹配我们之前保存的内容:
>>> arr
array([[ 0.80881898, 0.50553303, 0.03859795, ..., 0.05850996,
0.9174782 , 0.48671767],
[ 0.79715979, 0.81465744, 0.93529834, ..., 0.53577085,
0.59098735, 0.22716425],
[ 0.49570713, 0.09599001, 0.74023709, ..., 0.85172897,
0.05066641, 0.10364143],
...,
[ 0.89720137, 0.60616688, 0.62966729, ..., 0.6206728 ,
0.96160519, 0.69746633],
[ 0.59276237, 0.71586014, 0.35959289, ..., 0.46977027,
0.46586237, 0.10949621],
[ 0.8075795 , 0.70107856, 0.81389246, ..., 0.92068768,
0.38013495, 0.21489793]])
>>>
答案 1 :(得分:2)
默认的pickle方法提供纯粹的ascii输出。要获得(更好)性能,请使用可用的最新版本。版本2及更高版本是二进制的,如果内存对我有用,则允许numpy数组将其缓冲区直接转储到流中,而无需添加额外的操作。
要选择要使用的版本,请在pickle时添加可选参数(在unpickling时不需要指定它),例如pkl.dumps(data, 2)
。
要选择最新版本,请使用pkl.dumps(data, -1)
请注意,如果使用不同的python版本,则需要指定支持的最低版本。 有关不同版本的详细信息,请参阅Pickle documentation
答案 2 :(得分:1)
有一种方法tobytes
,根据我的基准,它比其他方法要快。
带着一粒盐,因为我的一些实验可能会被误导或完全错误,但这 是一种将numpy数组转储为字符串的方法。
请记住,您将需要带外一些其他数据,主要是数组的数据类型及其形状。那可能是一个破坏交易的事情,或者可能不是相对的。通过调用.fromstring(..., dtype=...).reshape(...)
很容易恢复原始形状。
编辑:一个可能不完整的示例
##############
# Generation #
##############
import numpy as np
arr = np.random.randint(1, 7, (4,6))
arr_dtype = arr.dtype.str
arr_shape = arr.shape
arr_data = arr.tobytes()
# Now send / store arr_dtype, arr_shape, arr_data, where:
# arr_dtype is string
# arr_shape is tuple of integers
# arr_data is bytes
############
# Recovery #
############
arr = np.frombuffer(arr_data, dtype=arr_dtype).reshape(arr_shape)
我不考虑列/行的顺序,因为我知道numpy支持有关该功能的事情,但我从未使用过。如果要支持/需要以特定方式排列内存(关于多维数组的行/列),则可能需要在某些时候考虑到这一点。
此外:frombuffer
不会复制缓冲区数据,而是创建numpy结构作为视图(也许不完全是这样,但是您知道我的意思)。如果这是不希望的行为,则可以使用fromstring(已弃用,但似乎可以在1.19上运行),也可以使用frombuffer
后跟np.copy
。