如何将Numpy savetxt的存储类型从int16改为int8?
解决Numpy savetxt存储二进制值时文件偏大的问题
你提到的情况其实是对np.savetxt的工作逻辑有点误解——savetxt是将数组保存为文本文件,并不存在“用int16数据类型存储”的说法,你看到的每个值占2字节,本质是默认格式输出带来的额外字符(比如空格、换行符)导致的。咱们一步步拆解问题和解决方案:
为什么原代码会让文件变大?
当你用fmt='%d'时,Numpy会按默认的文本格式规则输出:
- 对于一维数组,默认每行输出一个元素,格式是
数字+换行符(比如0\n),这就占了2字节; - 对于二维数组,默认用空格分隔元素,每个元素是
数字+空格(比如1),同样占2字节,最后一个元素再加换行符。
哪怕你的数组是np.int8类型,文本存储的是字符形式的数字,和原数组的数值类型没有直接关联——%d只是指定了数字的文本格式,不是二进制存储的类型。
优化方案:让文件更紧凑
1. 调整文本格式参数(适合需要文本文件的场景)
如果你的需求就是存成文本文件(方便查看或其他工具读取),可以通过调整fmt和delimiter参数来压缩空间:
对于只包含0和1的二进制数组,用fmt='%1d'强制每个数字只占1个字符宽度,结合delimiter=''去掉分隔符,这样每个数字仅占1字节:
import numpy as np import os import math def convert_size(size_bytes): if size_bytes == 0: return "0B" size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") i = int(math.floor(math.log(size_bytes, 1024))) p = math.pow(1024, i) s = round(size_bytes / p, 2) return "%s %s" % (s, size_name[i]) # 测试用的int8二进制数组 Arr = np.random.randint(0, 2, size=100000, dtype=np.int8) filepath = 'binary_values.txt' # 原方式 np.savetxt(filepath, Arr, fmt='%d') print(f"原文件大小: {convert_size(os.path.getsize(filepath))}") # 优化方式 np.savetxt(filepath, Arr, fmt='%1d', delimiter='') print(f"优化后文件大小: {convert_size(os.path.getsize(filepath))}")
运行后你会发现优化后的文件大小几乎减半(去掉了换行符或空格的额外字节)。如果是二维数组,这个方式会让每行变成连续的0/1字符串,非常紧凑。
2. 直接存为二进制文件(最省空间)
如果不需要文本格式,只是想高效存储二进制值,那别用savetxt了,直接用Numpy的二进制存储方法:
np.save:保存为.npy格式(带数组元数据,方便直接用np.load读取)Arr.tofile():保存为原始二进制文件(仅存数据,最节省空间)
示例代码:
# 存为.npy二进制文件 np.save('binary_values.npy', Arr) print(f".npy文件大小: {convert_size(os.path.getsize('binary_values.npy'))}") # 存为原始二进制文件 Arr.tofile('binary_values.raw') print(f"原始二进制文件大小: {convert_size(os.path.getsize('binary_values.raw'))}")
原始二进制文件的大小正好是数组元素个数×1字节(因为是np.int8),是最节省空间的存储方式。
内容的提问来源于stack exchange,提问作者Mike




