我需要创建一个超过MATLAB数组大小限制的大型二进制矩阵。
默认情况下,MATLAB将整数数组创建为双精度数组。但由于我的矩阵是二进制的,我希望有一种方法来创建一个位数组而不是双精度数并消耗更少的内存。
我创建了一个随机二进制矩阵B
并将其转换为逻辑数组A = randi([0 1], 1000, 1000);
B=logical(A);
:
{{1}}
我将两个都保存为.mat文件。它们占用了我计算机上相同的空间,所以我不认为MATLAB使用更紧凑的逻辑数据类型,这看起来非常浪费。有什么想法吗?
答案 0 :(得分:3)
你肯定这些变量是否占用相同的空间? logical
数据矩阵/数组本身就是每个数字1个字节,其中randi
是double
精度,即每个数字8个字节。对whos
的简单调用将显示每个变量占用多少内存:
>> A = randi([0 1], 1000, 1000);
>> B = logical(A);
>> whos
Name Size Bytes Class Attributes
A 1000x1000 8000000 double
B 1000x1000 1000000 logical
如您所见,A
需要8 x 1000 x 1000 = 8M字节,其中B
占用1 x 1000 x 1000 = 1M字节。他们之间肯定会节省内存。
逻辑的缺点是每个数字需要1个字节,而您正在寻找1 位。我能想到的最好的事情是使用无符号整数类型和N
的交错块 - 其中N
是数据类型的关联位精度,所以{ {1}}等成为单个交错数组。因此,每个数字可以交错32位,您可以保存这个最终矩阵。
事实上,这就是Java在使用uint8, uint16, uint32
类读取图像时打包彩色像素的方式。 RGB图像中的每个像素是24位,每个颜色通道有8位 - 红色,绿色和蓝色。每个像素表示为红色,绿色和蓝色的比例,并且它们将8位的三个连接成单个24位整数。通常,整数表示为32位,因此您可能认为有8个额外位被浪费。事实上, alpha通道表示每个颜色像素的透明度,而另一个8位代表这一点。如果不使用透明度,则假设这些都是1,因此这4对8位的集合构成每像素32位。但是,有一些压缩算法可以将每个像素的平均大小减小到每像素大小不到32位,但这超出了我所说的范围。
回到我们的讨论,以位形式表示这个二进制矩阵的一种方法可能是BufferedImage
循环,如下所示:
for
请记住,这只适用于元素总数可以被32整除的矩阵。我不会讨论如何处理它不是因为我只想说明你的观点可以做你所要求的,但它需要一些操纵。你的1000 x 1000 = 1M的情况肯定可以被32整除(你得到1M / 32 = 31250),所以这将有效。
这可能不是最优化的代码,但它得到了重点。基本上,我们从左到右依次列出32个数字(0/1)的块,并确定该数字的32位无符号整数表示。然后,我们将其存储在矩阵Abin = zeros(1, ceil(numel(A)/32), 'uint32');
for ii = 1 : numel(Abin)
val = A((ii-1)*32 + 1:ii*32);
dec = bin2dec(sprintf('%d', val));
Abin(ii) = dec;
end
中的单个位置。考虑到1000 x 1000矩阵,最终得到的是31250 32位无符号整数,对应于1000 x 1000 位,或1M位= 125,000字节。
现在尝试查看每个变量的大小:
Abin
要执行重建,请尝试:
>> whos
Name Size Bytes Class Attributes
A 1000x1000 8000000 double
Abin 1x31250 125000 uint32
B 1000x1000 1000000 logical
也不是最优化的,但它得到了重点。给定我们之前计算的“压缩”矩阵Arec = zeros(size(A));
for ii = 1 : numel(Abin)
val = dec2bin(Abin(ii), 32) - '0';
Arec((ii-1)*32 + 1:ii*32) = val(:);
end
,对于每个元素,我们重建原始32位数,然后将这些数字分配给存储在Abin
中的32位块。
您可以验证Arec
确实等于原始矩阵Arec
:
A
另外,请使用>> isequal(A, Arec)
ans =
1
whos
答案 1 :(得分:1)
您正在以压缩文件格式存储数据。对于版本7.0和7.3中的mat文件,使用gzip压缩。未压缩的数据具有不同的大小,但在压缩之后,两者都被压缩到大致相同的大小。发生这种情况是因为两个数据只包含0和1,可以高效压缩。