2010-11-24 46 views
16

¿Alguien aquí sabe cómo eliminar una variable de un archivo matlab? Sé que puede agregar variables a un archivo matlab existente utilizando el método save -append, pero no hay documentación sobre cómo eliminar variables del archivo.borrar variables de un archivo .mat

Antes de que alguien diga, "solo guárdelo", es porque estoy guardando pasos intermedios de procesamiento en el disco para aliviar problemas de memoria, y al final habrá casi 10 GB de datos intermedios por rutina de análisis. ¡Gracias!

Respuesta

13

Curiosamente, puede utilizar la opción -append con SAVE-efectivamente datos de borrado de un archivo .mat. Tenga en cuenta este extracto de la documentación (negrita añadida por mí):

Para MAT-archivos, -append añade nuevas variables al archivo o reemplaza los valores guardados de las variables existentes con los valores del espacio de trabajo.

En otras palabras, si una variable en el archivo de .mat se llama A, puede ahorrar más de esa variable con una nueva copiade A (que ha establecido a []) utilizando el -append opción. Todavía habrá una variable llamada A en el archivo .mat, pero estará vacía y, por lo tanto, reducirá el tamaño total del archivo.

He aquí un ejemplo:

>> 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 

El tamaño del archivo será de unos 7,21 MB. Ahora haga esto:

>> 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 

Y ahora el tamaño del archivo será de alrededor de 169 bytes. La variable todavía está allí, pero está vacía.

+2

+1 para la solución inteligente! – Jonas

1

La única forma de hacer esto que yo sé es usar la función de API de archivo MAT matDeleteVariable. Supongo que sería bastante fácil escribir una rutina Fortran o C para hacer esto, pero parece mucho esfuerzo para algo que debería ser mucho más fácil.

+0

Guau, espero que no sea la única manera de hacerlo, aunque gracias por señalarlo. Ha pasado un tiempo desde que escribí algo en c ... Estoy medio tentado de intentar escribir la rutina c que mencionas solo por las patadas. – eykanal

+0

@eykanal: Espero que no sea la única manera también. Pero nadie nos ha dicho de la manera mucho más directa de hacerlo desde la ventana de comandos. –

+2

Podría haber sido intencional para no hacer esto más conveniente. El diseño contiguo del formato de archivo MAT significa que cuando elimina una variable, debe dejar "basura" en su lugar y perder espacio en el disco, o posiblemente reescribir gran parte del archivo. Algo así como el costo de eliminación de O (n) para un elemento en una matriz, pero que cuesta la E/S del disco. La exposición de una función de supresión de variables podría ser una invitación para que el usuario poco sofisticado realice accidentalmente muchas E/S innecesarias. –

0

Le sugiero que cargue las variables del archivo .mat que desea conservar y guárdelas en un nuevo archivo .mat. Si es necesario, puede cargar y guardar (usando '-append') en un bucle.

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

Eso es lo que estoy haciendo, pero esa es una solución arriesgada. Estoy realmente sorprendido de que no haya una forma directa de hacer esto. – eykanal

+0

@eykanal: Aparentemente, no hay suficientes personas que alguna vez necesiten tal característica. – Jonas

10

10 GB de datos? Actualizar los archivos MAT multivariables podría ser costoso debido a la sobrecarga del formato MAT. Considere dividir los datos y guardar cada variable en un archivo MAT diferente, utilizando directorios para la organización si es necesario. Incluso si tuviera una función conveniente para eliminar variables de un archivo MAT, sería ineficiente. Las variables en un archivo MAT se muestran contiguamente, por lo que reemplazar una variable puede requerir leer y escribir gran parte del resto. Si están en archivos separados, puede simplemente eliminar el archivo completo, que es rápido.

Para ver esto en acción, pruebe este código, piénselo en el depurador mientras usa algo como Process Explorer (en Windows) para controlar su actividad de E/S.

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; 

En mi máquina, los resultados se ven así.(Lectura y escritura son acumulativos, El tiempo es por operación.)

    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 

en cuenta que la actualización de la pequeña variable x es más cara que la actualización de la gran y. Gran parte de esta actividad de E/S es trabajo de limpieza "redundante" para mantener organizado el formato de archivo MAT, y desaparecerá si cada variable está en su propio archivo.

Además, intente mantener estos archivos en el sistema de archivos local; será mucho más rápido que las unidades de red. Si necesitan conectarse a una unidad de red, considere guardar() y cargar() en archivos temporales locales (tal vez elegidos con tempname()) y luego copiarlos a/desde la unidad de red. El ahorro y la carga de Matlab tienden a ser mucho más rápidos con los sistemas de archivos locales, lo suficiente como para que la operación de guardar/cargar más una copia local sea una ganancia neta sustancial.


Aquí es una implementación básica que le permitirá guardar las variables en archivos separados utilizando el familiar save() y la carga() las firmas. Están prefijados con "d" para indicar que son las versiones basadas en el directorio. Usan algunos trucos con evalin() y assignin(), así que pensé que valdría la pena publicar el código completo.

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 

Aquí está el equivalente a 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() es el equivalente de 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$', ''); 

Y ddelete() para eliminar las variables individuales como usted solicitó.

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 
+0

Curiosamente, estoy usando una caja de herramientas de análisis de datos en particular, y recomiendan hacer lo que dices; usando un solo archivo para cada variable. No lo hice porque no vi el razonamiento, pero tu publicación detallada lo explica. ¡Gracias! – eykanal

Cuestiones relacionadas