使用 MAT 文件中的索引加载特定变量

Posted

技术标签:

【中文标题】使用 MAT 文件中的索引加载特定变量【英文标题】:Loading specific variable with indexing from a MAT-file 【发布时间】:2011-03-17 14:55:06 【问题描述】:

我在一台有大量 RAM 的机器上有一个框架,它可以生成带有一个非常大且专门命名的矩阵的 MAT 文件。这个矩阵的计算只进行一次并且需要很多时间。最后存储到磁盘上的一个 MAT 文件中。

在使用阶段,应加载此 MAT 文件。问题是我不需要所有数据 - 只需要从该矩阵中选择某些列。

例如,我在大小为 [500x250000] 的文件 crfh.mat 中有一个矩阵“符号”并键入 double。我可能有兴趣仅使用该矩阵中的“ids”加载向量:

sign(:, ids)

有没有办法做到这一点?我在网上搜索,似乎没有人表示需要这种功能。我正在考虑编写一个 MEX 函数 select_mat() ,例如:

sign_sub = select_mat(mat_file, var_name, ids);

【问题讨论】:

【参考方案1】:

如果您有一个非常大的矩阵,您只想加载其中的一部分,我不会将其保存为 .MAT 文件。将矩阵写入自己的二进制文件会更有效。然后,您可以使用 FSEEK 之类的函数跳到文件中的各个索引点并仅读取您需要的内容。例如,我们首先使用函数FWRITE将一个较小的样本矩阵保存到二进制文件中:

>> M = magic(5)  %# A sample matrix
M =
    17    24     1     8    15
    23     5     7    14    16
     4     6    13    20    22
    10    12    19    21     3
    11    18    25     2     9

>> fid = fopen('bigmatrix.dat','w');  %# Open the file for writing
>> fwrite(fid,size(M),'uint8','l');   %# Write the matrix size (needed later) as
                                      %#   2 unsigned 8-bit (1-byte) integers
>> fwrite(fid,M,'uint8','l');         %# Write the matrix data as unsigned 8-bit
                                      %#   (1-byte) integers
>> fclose(fid);                       %# Close the file

现在,我们可以使用函数FREAD 和FSEEK 仅读取第三列:

>> colIndex = 3;
>> fid = fopen('bigmatrix.dat','r');    %# Open the file for reading
>> sizeM = fread(fid,2,'uint8','l');    %# Read the first two bytes to get the
                                        %#   size of the matrix in the file
>> fseek(fid,sizeM(1)*(colIndex-1),0);  %# Seek forward by an amount of two
                                        %#   columns worth of bytes
>> colData = fread(fid,sizeM(1),'uint8','l');  %# Read column 3 data
>> fclose(fid);                         %# Close the file
>> disp(colData)                        %# Confirm that the right column was read
     1
     7
    13
    19
    25

这只是一个简单的例子。您可能希望将其他信息写入文件(即header information),例如矩阵中每个值的字节大小或数据类型。这看起来似乎比将内容转储到 .MAT 文件需要更多的工作,而且确实如此,但如果文件 IO 操作的效率是一个大问题,那么最好创建自己的文件格式来处理这种情况下的数据。

【讨论】:

【参考方案2】:

您可以从包含多个变量的.mat 文件中加载特定变量。但是,我认为您不能只从 MATLAB 的变量中加载一组任意索引。

也就是说,如果您的问题属于只需要访问特定行/列的类型,那么我可能会为您提供解决方法。

您可以从矩阵创建struct,将每列作为单独的字段,然后使用-struct 选项保存.mat 文件,以便将每个字段保存为单独的变量。这样一来,你就可以拿出你想要的那个了。

dummy=randn(100,200);%# this is a test matrix
[dim1,dim2]=size(dummy);

dummyCell=mat2cell(dummy,dim1,ones(dim2,1));%# create a cell from the matrix
fieldNames=strcat(repmat('col',1,dim2),cellfun(@num2str,mat2cell(1:dim2,1,ones(dim2,1)),'UniformOutput',false));%# generate fieldnames for the struct

dummyStruct=cell2struct(dummyCell,fieldNames,2);%# create the struct
save('myDummyFile','-struct','dummyStruct')

我不知道直接将矩阵转换为结构的方法。因此,您首先将每一列拆分为单元格(排序是因为您指出您需要访问这些列。如果您需要行,则必须进行切换)。这是在单元格dummyCell 中。现在要保存到结构,我们需要生成字段名称。这是在字符串单元格fieldNames 中。它会生成col1col2 等形式的字段名称...如果需要,您可以将其命名为有意义的名称。然后我们将cell 转换为struct,方法是将每个单元格分配给相应的字段名称。最后,使用-struct 选项保存 mat 文件,该选项告诉 MATLAB 将每个字段保存为单独的变量。所有这些都应该在您的程序保存巨大的 mat 文件时完成。现在,如果您需要访问,比如说col52,您只需load('myDummyFile','col52')。如果需要,您还可以加载多个。

请记住,如果您对索引要求(即每行/每列)有一个顺序,如果您需要访问矩阵中的任意索引,那么这将很有效,那么这将不起作用。创建单元/结构并保存它时可能会有一些相关的开销。但是,如果您只保存一次,但经常访问,这将得到回报。

如果您的矩阵很大(按照今天的标准,500x250000 并不是那么大),您必须注意这种方法的内存问题,因为我们将整个矩阵复制到一个单元格和结构中。我一步一步地编写它,以便更清楚地理解,但您可以通过从dummy 创建一个单元格并将其分配给自身以及类似地分配给结构来减少重复。但是,这只会将副本数减少 1,因为 Matlab 仍然需要将变量复制到内存中,以便在操作后分配给自己。

【讨论】:

以上是关于使用 MAT 文件中的索引加载特定变量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 中的变量删除列表中特定索引处的元素? [复制]

MatFile 对象仅支持 '()' 索引

将 mat 文件加载到 matlab 并稍后在 .m 文件中使用变量

在不加载 .mat 文件的情况下检查变量是不是在 .mat 文件中的快速方法? 'who'/'whos' 并不比加载快.. 比 'who' 更好的选择?

kendo ui 在首次加载期间选择特定的索引/文本

OpenCV C++:根据存储在 int 向量中的索引为 Mat 类型数据创建列范围