如何使用自定义编解码器将numpy数组另存为字节?

人性化

我有一个类型int8和形状的numpy数组(100,100)我使用霍夫曼编码来找到一种最大有效的方式来对其内容进行编码。对于我的特定用例,我尝试保存的值大致在0附近正态分布,标准偏差约为5,但是此问题适用于以任何分布来最佳保存ndarray。就我而言,在极少数情况下可以观察到高达-20或20的极值。显然,霍夫曼编码这种类型的数组比使用标准的8位整数更节省空间。我的问题是如何做到这一点。

我尝试使用np.save()和使用Pickle,但无法获得所需的效率。具体来说,对于形状数组,(100,100)我使用会得到10,128字节大小的文件np.save(),这对于每个整数1字节加上开销来说是有意义的。使用pickle,我得到的文件大小为10,158字节,大致相同。但是,基于我的霍夫曼编码方案,我应该能够在我的特定测试用例(如下所示)中以144个字节对数组内容进行编码!!(不包括开销)

我尝试将数组中的每个整数映射到其最佳字节字符串,所以我有一个字节数组(type S12),然后保存该数组,但同时使用np.save()pickle和pickle得到了一个118kb的文件,因此显然不起作用。

谢谢您的帮助!

复制我确切的测试用例的代码:

import pickle
import numpy as np

# Seed random number generator
np.random.seed(1234)

# Build random normal array and round it 
test_array = np.random.normal(0, 5, size=(100, 100))
test_array = np.round(test_array).astype(np.int8)

# Set encoding dictionary
encoding_dict = {6: b'0000',
 -8: b'00010',
 8: b'00011',
 5: b'0010',
 -5: b'0011',
 12: b'0100000',
 -13: b'01000010',
 14: b'010000110',
 -15: b'0100001110',
 -14: b'0100001111',
 10: b'010001',
 7: b'01001',
 -4: b'0101',
 4: b'0110',
 -7: b'01110',
 11: b'0111100',
 -11: b'0111101',
 -12: b'01111100',
 13: b'011111010',
 -19: b'011111011000',
 -18: b'011111011001',
 -16: b'01111101101',
 -17: b'011111011100',
 16: b'011111011101',
 15: b'01111101111',
 -10: b'0111111',
 -3: b'1000',
 -6: b'10010',
 -9: b'100110',
 9: b'100111',
 3: b'1010',
 -2: b'1011',
 1: b'1100',
 2: b'1101',
 -1: b'1110',
 0: b'1111'}

# Save using different methods
np.save('test.npy', test_array)
with open('test.pkl', 'wb') as file:
    pickle.dump(test_array, file)

# Try converting to bytes and then saving
bytes_array = np.array([encoding_dict[key] for key in test_array.flatten()]).reshape(test_array.shape)
np.save('test_bytes.npy', bytes_array)
with open('test_bytes.pkl', 'wb') as file:
    pickle.dump(bytes_array, file)

# See how many bytes it should take
tmp_flat = test_array.flatten()
tmp_bytes = np.zeros_like(tmp_flat)
for i in range(len(tmp_bytes)):
    tmp_bytes[i] = len(encoding_dict[tmp_flat[i]]) / 8
print(tmp_bytes.sum())
疯狂物理学家

您的错误在这里:

tmp_bytes = np.zeros_like(tmp_flat)

tmp_flat是一个int8数组,因此在tmp_bytes[i] = len(encoding_dict[tmp_flat[i]]) / 8将float值转换为int时,该语句将截断很多数字。用类似以下内容替换违规行:

tmp_bytes = np.zeros(tmp_flat.shape, np.single)

但是为了展示如何进行压缩:我建议使用np.packbits,它将为您创建一个5493字节的数组。

# Make a string of all the data
s = b''.join(encoding_dict[key] for key in test_array.ravel())
# Convert the string into an array
a = np.array(list(map(int, s.decode('ascii'))))
# pack it
result = np.packbits(a)

该语句a = ...正在做很多额外的工作,因为它先对数据进行解码,然后将其复制,然后将一个字符串转换为整数倍,等等。这是一个更长但更有效的方法:

s = bytearray(b'').join(encoding_dict[key] for key in test_array.ravel())
a = np.array(s)
a -= ord('0')    # A now contains just 0 and 1
result = np.packbits(a)

存放此数组时,请确保包含所需的位数,而不是字节数。您可以使用来解压缩为二进制字符串np.unpackbits,该字符串支持count专门用于此目的参数(顺便说一句,我的补充)。

最后一点,ravel而不是flatten在可能时候使用后者通常会复制,而前者通常不会。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

自定义Python Charmap编解码器

使用自定义颜色将numpy数组另存为单通道png

如何在Quarkus中托管自定义Netty编解码器?

如何正确创建自定义文本编解码器?

GridFS:找不到自定义类的编解码器

JTS(GeoTools)的自定义MongoDB编解码器?

Java:编写自定义视频编解码器的指南

用于案例类的Scala mongo驱动程序自定义编解码器

将自定义编解码器添加到CassandraConnector

Scala 中的 DSE 5.0 自定义编解码器 - Intellij 无法编译

vertx IllegalArgumentException:类型没有消息编解码器-如何为自定义类型创建使用者

我如何(或有可能)将AVC编解码器配置文件和级别转换为MIME编解码器定义?

如何使用Opus编解码器编码音频?

如何使用libvlc检索编解码器信息?

使用自定义对象映射器在Vertx 4.0中注册Jackson编解码器的位置在哪里

自定义编解码器或PojoCodec可能需要显式配置和注册以处理此类型

Java Cassandra Datastax驱动程序自定义编解码器不处理集合类型

关于音频编解码器术语的定义

PIP安装Numpy引发错误“ ASCII编解码器无法解码字节0xe2”

PIP安装Numpy引发错误“ ascii编解码器无法解码字节0xe2”

如何将numpy数组另存为Tensorflow变量

如何使用ffmpeg / avconv使用wmv1编解码器将任何视频转换为.avi?

将Numpy数组另存为图像

免费编解码器:如何在Xenial下使用FFmpeg将mp4转换为ogv?

使用Python C扩展时如何解决“ UnicodeDecodeError:'utf-8'编解码器无法解码字节”的问题?

如何禁用Grails createLink编解码器(编码)?

如何找到AVI的编解码器?

如何启用视频和音频编解码器?

如何安装常见的媒体编解码器