将numpy数组转储到字符串

时间:2017-05-11 21:11:51

标签: python arrays numpy pickle

我需要组织一个包含命名数据块的数据文件。数据是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,但对我来说,如何使用这个转储缓冲区来获取数组是不明显的。

3 个答案:

答案 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