【问题标题】:deleting variables from a .mat file从 .mat 文件中删除变量
【发布时间】:2011-05-15 03:50:32
【问题描述】:

这里有人知道如何删除 matlab 文件中的变量吗?我知道您可以使用 save -append 方法将变量添加到现有的 matlab 文件中,但是没有关于如何从文件中删除变量的文档。

在有人说“只需保存它”之前,这是因为我将中间处理步骤保存到磁盘以缓解内存问题,最终每个分析例程将有近 10 GB 的中间数据。谢谢!

【问题讨论】:

    标签: matlab mat-file


    【解决方案1】:

    10 GB 数据?由于 MAT 格式开销,更新多变量 MAT 文件可能会变得昂贵。考虑拆分数据并将每个变量保存到不同的 MAT 文件中,必要时使用目录进行组织。即使您有一个方便的函数来从 MAT 文件中删除变量,它也是低效的。 MAT 文件中的变量是连续排列的,因此替换一个变量可能需要读取和写入其余的大部分变量。如果它们在单独的文件中,您可以删除整个文件,速度很快。

    要查看实际情况,请尝试此代码,在调试器中单步执行它,同时使用 Process Explorer(Windows 上)之类的工具来监控其 I/O 活动。

    function replace_vars_in_matfile
    
    x = 1;
    % Random dummy data; zeros would compress really well and throw off results
    y = randi(intmax('uint8')-1, 100*(2^20), 1, 'uint8');
    
    tic; save test.mat x y; toc;
    x = 2;
    tic; save -append test.mat x; toc;
    y = y + 1;
    tic; save -append test.mat y; toc;
    

    在我的机器上,结果如下所示。 (读和写是累积的,时间是每次操作的。)

                        Read (MB)      Write (MB)       Time (sec)
    before any write:   25             0
    first write:        25             105              3.7
    append x:           235            315              3.6
    append y:           235            420              3.8
    

    请注意,更新小的 x 变量比更新大的 y 更昂贵。这种 I/O 活动的大部分是“冗余”的内务工作,以保持 MAT 文件格式的组织性,如果每个变量都在自己的文件中,就会消失。

    另外,尽量将这些文件保存在本地文件系统上;它会比网络驱动器快得多。如果他们需要在网络驱动器上运行,请考虑对本地临时文件(可能使用 tempname() 选择)执行 save() 和 load(),然后将它们复制到网络驱动器/从网络驱动器复制它们。使用本地文件系统时,Matlab 的保存和加载往往要快得多,这足以让本地保存/加载加上一个副本成为一个巨大的净赢。


    这是一个基本实现,它允许您使用熟悉的 save() 和 load() 签名将变量保存到单独的文件中。它们以“d”为前缀,表示它们是基于目录的版本。他们对 evalin() 和 assignin() 使用了一些技巧,所以我认为发布完整代码是值得的。

    function dsave(file, varargin)
    %DSAVE Like save, but each var in its own file
    %
    % dsave filename var1 var2 var3...
    if nargin < 1 || isempty(file); file = 'matlab';  end
    [tfStruct,loc] = ismember({'-struct'}, varargin);
    args = varargin;
    args(loc(tfStruct)) = [];
    if ~all(cellfun(@isvarname, args))
        error('Invalid arguments. Usage: dsave filename <-struct> var1 var2 var3 ...');
    end
    if tfStruct
        structVarName = args{1};
        s = evalin('caller', structVarName);
    else
        varNames = args;
        if isempty(args)
            w = evalin('caller','whos');
            varNames = { w.name };
        end
        captureExpr = ['struct(' ...
            join(',', cellfun(@(x){sprintf('''%s'',{%s}',x,x)}, varNames)) ')'];
        s = evalin('caller', captureExpr);
    end
    
    % Use Java checks to avoid partial path ambiguity
    jFile = java.io.File(file);
    if ~jFile.exists()
        ok = mkdir(file);
        if ~ok; 
            error('failed creating dsave dir %s', file);
        end
    elseif ~jFile.isDirectory()
        error('Cannot save: destination exists but is not a dir: %s', file);
    end
    names = fieldnames(s);
    for i = 1:numel(names)
        varFile = fullfile(file, [names{i} '.mat']);
        varStruct = struct(names{i}, {s.(names{i})});
        save(varFile, '-struct', 'varStruct');
    end
    
    function out = join(Glue, Strings)
    Strings = cellstr(Strings);
    if length( Strings ) == 0
        out = '';
    elseif length( Strings ) == 1
        out = Strings{1};
    else
        Glue = sprintf( Glue ); % Support escape sequences
        out = strcat( Strings(1:end-1), { Glue } );
        out = [ out{:} Strings{end} ];
    end
    

    这是 load() 等效项。

    function out = dload(file,varargin)
    %DLOAD Like load, but each var in its own file
    if nargin < 1 || isempty(file); file = 'matlab'; end
    varNames = varargin;
    if ~exist(file, 'dir')
        error('Not a dsave dir: %s', file);
    end
    if isempty(varNames)
        d = dir(file);
        varNames = regexprep(setdiff(ls(file), {'.','..'}), '\.mat$', '');
    end
    
    out = struct;
    for i = 1:numel(varNames)
        name = varNames{i};
        tmp = load(fullfile(file, [name '.mat']));
        out.(name) = tmp.(name);
    end
    
    if nargout == 0
        for i = 1:numel(varNames)
            assignin('caller', varNames{i}, out.(varNames{i}));
        end
        clear out
    end
    

    Dwhos() 等价于 whos('-file')。

    function out = dwhos(file)
    %DWHOS List variable names in a dsave dir
    if nargin < 1 || isempty(file); file = 'matlab'; end
    out = regexprep(setdiff(ls(file), {'.','..'}), '\.mat$', '');
    

    然后使用 ddelete() 删除您所要求的各个变量。

    function ddelete(file,varargin)
    %DDELETE Delete variables from a dsave dir
    if nargin < 1 || isempty(file); file = 'matlab'; end
    varNames = varargin;
    for i = 1:numel(varNames)
        delete(fullfile(file, [varNames{i} '.mat']));
    end
    

    【讨论】:

    • 有趣的是,我正在使用一个特定的数据分析工具箱,他们建议照你说的做;对每个变量使用一个文件。我没有这样做是因为我没有看到原因,但是您的详细帖子对此进行了解释。谢谢!
    【解决方案2】:

    有趣的是,您可以使用 -append 选项和 SAVE有效地从 .mat 文件中擦除数据。请注意文档中的这段摘录(我添加的粗体):

    对于 MAT 文件,-append 将新变量添加到文件中或用工作区中的值替换现有变量的保存值

    换句话说,如果您的 .mat 文件中的变量名为 A,您可以使用 Anew 副本保存该变量(您已设置为 @ 987654326@) 使用-append 选项。 .mat 文件中仍然会有一个名为A 的变量,但它会为空,从而减少总文件大小。

    这是一个例子:

    >> A = rand(1000);            %# Create a 1000-by-1000 matrix of random values
    >> save('savetest.mat','A');  %# Save A to a file
    >> whos -file savetest.mat    %# Look at the .mat file contents
      Name         Size                Bytes  Class     Attributes
    
      A         1000x1000            8000000  double
    

    文件大小约为 7.21 MB。现在这样做:

    >> A = [];                              %# Set the variable A to empty
    >> save('savetest.mat','A','-append');  %# Overwrite A in the file
    >> whos -file savetest.mat              %# Look at the .mat file contents
      Name      Size            Bytes  Class     Attributes
    
      A         0x0                 0  double
    

    现在文件大小约为 169 字节。变量还在,但它是空的。

    【讨论】:

      【解决方案3】:

      我建议您从要保留的 .mat 文件中加载变量,并将它们保存到新的 .mat 文件中。如有必要,您可以循环加载和保存(使用'-append')。

      S = load(filename, '-mat', variablesYouWantToKeep);
      save(newFilename,'-struct',S,variablesYouWantToKeep);
      %# then you can delete the old file
      delete(filename)
      

      【讨论】:

      • 这就是我正在做的,但这是一个笨拙的解决方法。我真的很惊讶似乎没有直接的方法可以做到这一点。
      • @eykanal:显然没有足够的人需要这样的功能。
      【解决方案4】:

      我知道的唯一方法是使用 MAT 文件 API 函数 matDeleteVariable。我想,编写一个 Fortran 或 C 例程来执行此操作会很容易,但对于应该更容易的事情来说,这似乎需要付出很多努力。

      【讨论】:

      • 哇,我希望这不是唯一的方法,尽管感谢您指出这一点。自从我用 c 写任何东西以来已经有一段时间了......我有点想尝试编写你提到的 c 例程,只是为了好玩。
      • @eykanal:我有点希望这也不是唯一的方法。但是还没有人告诉我们从命令窗口执行此操作的更直接的方法。
      • 可能故意不让这更方便。 MAT 文件格式的连续布局意味着当您删除一个变量时,您要么需要将“垃圾”留在原处并浪费磁盘空间,要么可能重写大部分文件。有点像数组中元素的 O(n) 删除成本,但会消耗磁盘 I/O。暴露一个 deletevariable 函数可能会诱使不成熟的用户意外地执行大量不必要的 I/O。
      猜你喜欢
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 2021-03-07
      • 2014-07-31
      • 2022-01-19
      • 2017-11-26
      • 2021-01-26
      • 1970-01-01
      相关资源
      最近更新 更多