удаление переменных из файла .mat

Кто-нибудь здесь знает, как удалить переменную из файла Matlab? Я знаю, что вы можете добавить переменные в существующий файл Matlab, используя метод save -append, но нет документации о том, как удалить переменные из файла.

Прежде чем кто-то скажет «просто сохраните», это потому, что я сохраняю промежуточные этапы обработки на диск, чтобы уменьшить проблемы с памятью, и в конце будет почти 10 ГБ промежуточных данных на процедуру анализа. Спасибо!


person eykanal    schedule 24.11.2010    source источник


Ответы (4)


Интересно, что вы можете использовать параметр -append с СОХРАНИТЬ в эффективно удалить данные из файла .mat. Обратите внимание на этот отрывок из документации (жирный шрифт добавлен мной):

Для MAT-файлов -append добавляет в файл новые переменные или заменяет сохраненные значения существующих переменных значениями в рабочей области.

Другими словами, если переменная в вашем файле .mat называется A, вы можете сохранить эту переменную с помощью новой копии A (которой вы установили значение []) с помощью параметра -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 МБ. Теперь сделайте это:

>> 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 байт. Переменная все еще там, но она пуста.

person gnovice    schedule 24.11.2010

10 ГБ данных? Обновление файлов MAT с несколькими переменными может стать дорогостоящим из-за накладных расходов на формат MAT. Рассмотрите возможность разделения данных и сохранения каждой переменной в другой файл MAT, используя каталоги для организации, если это необходимо. Даже если бы у вас была удобная функция для удаления переменных из MAT-файла, она была бы неэффективной. Переменные в файле MAT располагаются непрерывно, поэтому замена одной переменной может потребовать чтения и записи большей части остальных. Если они находятся в отдельных файлах, вы можете просто удалить весь файл, что быстро.

Чтобы увидеть это в действии, попробуйте этот код, выполняя его в отладчике, используя что-то вроде Process Explorer (в Windows) для отслеживания операций ввода-вывода.

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. Большая часть этой деятельности ввода-вывода является «избыточной» вспомогательной работой для поддержания организованного формата файла MAT и исчезнет, ​​если каждая переменная находится в своем собственном файле.

Кроме того, старайтесь хранить эти файлы в локальной файловой системе; это будет намного быстрее, чем сетевые диски. Если им нужно перейти на сетевой диск, подумайте о том, чтобы выполнить save() и load() для локальных временных файлов (возможно, выбранных с помощью tempname()), а затем скопировать их на сетевой диск или с него. Сохранение и загрузка 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
person Andrew Janke    schedule 24.11.2010
comment
Интересно, что я использую определенный набор инструментов для анализа данных, и они рекомендуют делать то, что вы говорите; используя один файл для каждой переменной. Я этого не делал, потому что не видел аргументации, но ваш подробный пост объясняет это. Спасибо! - person eykanal; 25.11.2010

Единственный известный мне способ сделать это — использовать функцию API MAT-файла matDeleteVariable. Я думаю, было бы довольно легко написать подпрограмму на Fortran или C, чтобы сделать это, но кажется, что это требует больших усилий для чего-то, что должно быть намного проще.

person High Performance Mark    schedule 24.11.2010
comment
Вау, я надеюсь, что это не единственный способ сделать это, хотя спасибо, что указали на это. Прошло некоторое время с тех пор, как я писал что-либо на c... У меня возник соблазн попытаться написать процедуру c, которую вы упомянули, просто для удовольствия. - person eykanal; 24.11.2010
comment
@eykanal: Я тоже надеюсь, что это не единственный способ. Но никто еще не рассказал нам о гораздо более простом способе сделать это из командного окна. - person High Performance Mark; 24.11.2010
comment
Возможно, это было сделано намеренно, чтобы не сделать это более удобным. Непрерывная компоновка файла формата MAT означает, что когда вы удаляете переменную, вам нужно либо оставить мусор на месте и тратить место на диске, либо, возможно, переписать большую часть файла. Вроде как стоимость удаления O(n) для элемента в массиве, но стоимость дискового ввода-вывода. Предоставление функции удаления переменной может быть приглашением для неискушенного пользователя случайно выполнить множество ненужных операций ввода-вывода. - person Andrew Janke; 24.11.2010

Я предлагаю вам загрузить переменные из файла .mat, который вы хотите сохранить, и сохранить их в новый файл .mat. При необходимости вы можете загрузить и сохранить (используя '-append') в цикле.

S = load(filename, '-mat', variablesYouWantToKeep);
save(newFilename,'-struct',S,variablesYouWantToKeep);
%# then you can delete the old file
delete(filename)
person Jonas    schedule 24.11.2010
comment
Это то, что я делаю, но это неуклюжий обходной путь. Я действительно удивлен, что, кажется, нет прямого способа сделать это. - person eykanal; 24.11.2010
comment
@eykanal: Видимо, просто не хватает людей, которым когда-либо нужна была такая функция. - person Jonas; 24.11.2010