Skip to content

Instantly share code, notes, and snippets.

@draplater
Last active August 16, 2024 09:52
Show Gist options
  • Select an option

  • Save draplater/95d00062b08894bb0938052e91ffe761 to your computer and use it in GitHub Desktop.

Select an option

Save draplater/95d00062b08894bb0938052e91ffe761 to your computer and use it in GitHub Desktop.
▶(技术博客)◀ 压缩算法对比实验:探索如何用更少的比特存储0-1023的数字

▶(技术博客)◀ 压缩算法对比实验:探索如何用更少的比特存储0-1023的数字

技术难度:★★★☆☆
有趣幽默程度:★★★★☆


1. 背景:0-1023的数字到底要用几个比特来存?

当我们处理大量0到1023的数字时,直接用 uint16 存储可能有点浪费。毕竟 uint16 是16比特,可以表示0到65535的数,而咱们的数字范围仅在0到1023内,理论上用10比特就够啦。问题是,Python的 numpy 只提供了 uint8uint16 这两种无符号整数类型,那如果我们用 uint16 存储然后压缩,能不能接近10比特/数字的效率呢?这是偶们今天要研究的重点!(* ̄▽ ̄)b

2. 初步实验:使用gzip压缩

首先,偶们使用 numpy 生成一个1000个0-1023范围内的数字数组,然后用 pickle 序列化,再用 gzip 压缩,看看效果肿么样~

import numpy as np
import pickle
import gzip

# 生成1000个0到1023之间的数字
data = np.random.randint(0, 1024, size=1000, dtype=np.uint16)

# 使用pickle序列化数据
pickled_data = pickle.dumps(data)

# 使用gzip压缩数据
compressed_data = gzip.compress(pickled_data)

# 计算大小
original_size = data.nbytes  # 原始大小
compressed_size = len(compressed_data)  # 压缩后大小

print(f"原始数据大小: {original_size} bytes")
print(f"压缩后数据大小: {compressed_size} bytes")

实验结果:
1000个数字的原始大小是 2000字节,gzip压缩后的数据大小是 1732字节。经过简单计算,压缩后每个数字需要约 13.86比特,比预期的10比特稍高。

3. 扩展实验:数据量增加到10000

偶们把数据量扩大到10000个,再来看看效果:

# 生成10000个数字的数组
large_data = np.random.randint(0, 1024, size=10000, dtype=np.uint16)

# 同样的序列化和gzip压缩
large_pickled_data = pickle.dumps(large_data)
large_compressed_data = gzip.compress(large_pickled_data)

# 计算大小
original_size = large_data.nbytes  # 原始大小
compressed_size = len(large_compressed_data)  # 压缩后大小

print(f"原始数据大小: {original_size} bytes")
print(f"压缩后数据大小: {compressed_size} bytes")

结果:
原始数据为 20000字节,gzip压缩后变为 15381字节,每个数字约 12.30比特,稍微好点儿,但还是离10比特有点距离……

4. 换用更厉害的压缩算法:xz

既然gzip不能带来突破,那咱们试试Google大厂推出的 xz 算法(lzma库实现),看看有木有改善:

import lzma

# 使用xz算法压缩
xz_compressed_data = lzma.compress(large_pickled_data)

# 计算xz压缩后的数据大小
compressed_size = len(xz_compressed_data)

print(f"xz压缩后的数据大小: {compressed_size} bytes")

结果:
xz 的压缩结果是 13868字节,每个数字约 11.09比特。更接近目标了呢~ ^_^

5. 再试试lz4压缩算法

最后,我们想试试另一个压缩算法 lz4,它以速度见长,不过实验环境中缺少该库……(某Jobsa: 捂脸ing)。但可以告诉你,lz4的使用方式类似,只需要安装 lz4 模块,然后执行以下代码:

import lz4.frame

# 使用lz4压缩
lz4_compressed_data = lz4.frame.compress(large_pickled_data)

# 计算lz4压缩后的数据大小
compressed_size = len(lz4_compressed_data)

print(f"lz4压缩后的数据大小: {compressed_size} bytes")

如果你有时间在自己的环境中试试lz4,欢迎把结果分享给偶们一起研究哦~

6. 总结:10比特之梦,仍在探索中

经过这些实验,虽然用更强的压缩算法确实能接近10比特/数字的效率,但达到理想状态还是有难度。不同算法的压缩效果取决于数据的特性和量级。如果你在实际项目中遇到类似问题,记得选最合适的压缩算法哦~

希望这篇小小的技术博客对你有所启发,也期待你们有更多的建议和想法分享给偶~ (づ ̄ ³ ̄)づ


End ^O^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment